@topconsultnpm/sdkui-react 6.21.0-dev2.34 → 6.21.0-dev2.35
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/lib/components/editors/TMTextBox.d.ts +0 -2
- package/lib/components/editors/TMTextBox.js +3 -3
- package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +0 -4
- package/lib/components/features/documents/TMMasterDetailDcmts.js +5 -6
- package/lib/components/features/documents/TMRelationViewer.d.ts +0 -13
- package/lib/components/features/documents/TMRelationViewer.js +6 -75
- package/lib/components/features/search/TMSearch.d.ts +2 -2
- package/lib/components/features/search/TMSearch.js +2 -2
- package/lib/components/features/search/TMSearchResult.d.ts +2 -2
- package/lib/components/features/search/TMSearchResult.js +20 -4
- package/lib/helper/SDKUI_Globals.d.ts +0 -16
- package/lib/helper/SDKUI_Globals.js +1 -16
- package/lib/helper/TMUtils.d.ts +0 -19
- package/lib/helper/index.d.ts +0 -1
- package/lib/helper/index.js +0 -1
- package/lib/hooks/useDcmtOperations.d.ts +2 -8
- package/lib/hooks/useDcmtOperations.js +20 -29
- package/lib/hooks/useDocumentOperations.d.ts +0 -4
- package/lib/hooks/useDocumentOperations.js +7 -75
- package/package.json +1 -1
- package/lib/components/features/documents/TMCopyToFolderForm.d.ts +0 -16
- package/lib/components/features/documents/TMCopyToFolderForm.js +0 -306
- package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +0 -15
- package/lib/components/features/documents/TMDownloadRelationViewerSection.js +0 -155
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +0 -18
- package/lib/components/features/documents/TMMergeToPdfForm.js +0 -164
- package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +0 -53
- package/lib/components/features/documents/copyAndMergeDcmtsShared.js +0 -263
- package/lib/helper/ZipManager.d.ts +0 -56
- package/lib/helper/ZipManager.js +0 -104
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { DownloadTypes } from '../../../ts';
|
|
4
|
-
import { calcResponsiveSizes, IconPlay, SDKUI_Globals, SDKUI_Localizator, } from '../../../helper';
|
|
5
|
-
import { DcmtOpers, GeneralRetrieveFormats, ResultTypes, RetrieveFileOptions, ValidationItem, } from '@topconsultnpm/sdk-ts';
|
|
6
|
-
import TMModal from '../../base/TMModal';
|
|
7
|
-
import { useDeviceType } from '../../base/TMDeviceProvider';
|
|
8
|
-
import TMTextBox from '../../editors/TMTextBox';
|
|
9
|
-
import TMButton from '../../base/TMButton';
|
|
10
|
-
import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
|
|
11
|
-
import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
|
|
12
|
-
import { TMLayoutWaitingContainer } from '../../base/TMWaitPanel';
|
|
13
|
-
import { TMSplitterLayout } from '../../base/TMLayout';
|
|
14
|
-
import { TMColors } from '../../../utils/theme';
|
|
15
|
-
import TMDownloadRelationViewerSection from './TMDownloadRelationViewerSection';
|
|
16
|
-
import { getDcmtInfosToDownload, getFloatingLabelStyle, isPdfExt, MIN_PDF_FOR_MERGE, SPLITTER_MIN, SPLITTER_START_65_35, } from './copyAndMergeDcmtsShared';
|
|
17
|
-
/**
|
|
18
|
-
* Form per l'unione di più documenti PDF in un singolo file.
|
|
19
|
-
* Condivide TMDownloadRelationViewerSection e gli helper in copyAndMergeDcmtsShared
|
|
20
|
-
* con TMCopyToFolderForm.
|
|
21
|
-
*/
|
|
22
|
-
const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationViewer, mergePdfManager }) => {
|
|
23
|
-
const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, } = useDcmtOperations();
|
|
24
|
-
const deviceType = useDeviceType();
|
|
25
|
-
const [pdfFileName, setPdfFileName] = useState('');
|
|
26
|
-
const [selectedItemsRelationViewer, setSelectedItemsRelationViewer] = useState([]);
|
|
27
|
-
const getTitle = () => {
|
|
28
|
-
const count = ` (${selectedDcmtInfos.length})`;
|
|
29
|
-
const modeLabelMap = {
|
|
30
|
-
onlySelected: 'Solo i documenti selezionati',
|
|
31
|
-
customized: 'Documenti di primo livello e i correlati selezionati',
|
|
32
|
-
};
|
|
33
|
-
const modeLabel = modeLabelMap[mode] || modeLabelMap.onlySelected;
|
|
34
|
-
return `Unisci in un file PDF - ${modeLabel}${count}`;
|
|
35
|
-
};
|
|
36
|
-
// ---- Validazione ----
|
|
37
|
-
const pdfValidationItems = [];
|
|
38
|
-
if (!pdfFileName.trim()) {
|
|
39
|
-
pdfValidationItems.push(new ValidationItem(ResultTypes.ERROR, 'Nome file PDF', SDKUI_Localizator.RequiredField));
|
|
40
|
-
}
|
|
41
|
-
// ---- Statistiche selezione PDF / non-PDF ----
|
|
42
|
-
const nonPdfSelectedItems = (() => {
|
|
43
|
-
if (showTMRelationViewer) {
|
|
44
|
-
return selectedItemsRelationViewer
|
|
45
|
-
.filter(i => i.isDcmt && !isPdfExt(i.fileExt))
|
|
46
|
-
.map(i => ({ key: `${i.tid}_${i.did}`, ext: i.fileExt ?? undefined }));
|
|
47
|
-
}
|
|
48
|
-
return selectedDcmtInfos
|
|
49
|
-
.filter(d => !isPdfExt(d.FILEEXT))
|
|
50
|
-
.map(d => ({ key: `${d.TID}_${d.DID}`, ext: d.FILEEXT }));
|
|
51
|
-
})();
|
|
52
|
-
const hasNonPdfSelected = nonPdfSelectedItems.length > 0;
|
|
53
|
-
const pdfSelectedCount = (() => {
|
|
54
|
-
if (showTMRelationViewer) {
|
|
55
|
-
return selectedItemsRelationViewer.filter(i => i.isDcmt && isPdfExt(i.fileExt)).length;
|
|
56
|
-
}
|
|
57
|
-
return selectedDcmtInfos.filter(d => isPdfExt(d.FILEEXT)).length;
|
|
58
|
-
})();
|
|
59
|
-
const hasEnoughPdfForMerge = pdfSelectedCount >= MIN_PDF_FOR_MERGE;
|
|
60
|
-
const isFormValid = () => pdfValidationItems.length === 0;
|
|
61
|
-
// ---- Recupero dei file PDF da unire (condiviso tra Esegui e Anteprima) ----
|
|
62
|
-
const collectPdfFilesToMerge = async () => {
|
|
63
|
-
const dcmtInfosToDownload = getDcmtInfosToDownload(selectedDcmtInfos, selectedItemsRelationViewer, showTMRelationViewer);
|
|
64
|
-
if (dcmtInfosToDownload.length === 0) {
|
|
65
|
-
TMMessageBoxManager.show({ message: 'Nessun documento selezionato.', buttons: [ButtonNames.OK] });
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
const nonPdfKeys = new Set(nonPdfSelectedItems.map(i => i.key));
|
|
69
|
-
const pdfDcmtInfosToDownload = dcmtInfosToDownload.filter(d => !nonPdfKeys.has(`${d.TID}_${d.DID}`));
|
|
70
|
-
if (pdfDcmtInfosToDownload.length === 0) {
|
|
71
|
-
TMMessageBoxManager.show({
|
|
72
|
-
message: 'Tra i documenti selezionati non è presente alcun file PDF: l\'unione non può essere eseguita.',
|
|
73
|
-
buttons: [ButtonNames.OK]
|
|
74
|
-
});
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
if (pdfDcmtInfosToDownload.length < MIN_PDF_FOR_MERGE) {
|
|
78
|
-
TMMessageBoxManager.show({
|
|
79
|
-
message: `Tra i documenti selezionati è presente un solo file PDF: per l'unione ne servono almeno ${MIN_PDF_FOR_MERGE}.`,
|
|
80
|
-
buttons: [ButtonNames.OK]
|
|
81
|
-
});
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
const pdfFiles = [];
|
|
85
|
-
const retrieveOptions = new RetrieveFileOptions();
|
|
86
|
-
retrieveOptions.retrieveReason = DcmtOpers.None;
|
|
87
|
-
retrieveOptions.generalRetrieveFormat = GeneralRetrieveFormats.Original;
|
|
88
|
-
retrieveOptions.invoiceRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
|
|
89
|
-
retrieveOptions.orderRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
|
|
90
|
-
const collectFileForMerge = async (file, _dcmtInfo) => {
|
|
91
|
-
pdfFiles.push(file);
|
|
92
|
-
};
|
|
93
|
-
await downloadDcmtsAsync(pdfDcmtInfosToDownload, DownloadTypes.Dcmt, 'download', collectFileForMerge, undefined, true, retrieveOptions, false);
|
|
94
|
-
if (pdfFiles.length === 0) {
|
|
95
|
-
TMMessageBoxManager.show({ message: 'Nessun file disponibile per l\'unione.', buttons: [ButtonNames.OK] });
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
return pdfFiles;
|
|
99
|
-
};
|
|
100
|
-
// ---- Esecuzione: scarica i PDF e li unisce ----
|
|
101
|
-
const run = async () => {
|
|
102
|
-
if (pdfValidationItems.length > 0) {
|
|
103
|
-
TMMessageBoxManager.show({ message: 'Per favore, correggi gli errori prima di procedere.', buttons: [ButtonNames.OK] });
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (!mergePdfManager) {
|
|
107
|
-
TMMessageBoxManager.show({ message: 'La funzionalità di unione PDF non è disponibile.', buttons: [ButtonNames.OK] });
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const pdfFiles = await collectPdfFilesToMerge();
|
|
111
|
-
if (!pdfFiles)
|
|
112
|
-
return;
|
|
113
|
-
const finalName = pdfFileName.trim().toLowerCase().endsWith('.pdf')
|
|
114
|
-
? pdfFileName.trim()
|
|
115
|
-
: pdfFileName.trim() + '.pdf';
|
|
116
|
-
try {
|
|
117
|
-
await mergePdfManager.mergeAndDownload(pdfFiles, finalName);
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
console.error('Errore durante l\'unione dei PDF:', err);
|
|
121
|
-
TMMessageBoxManager.show({ message: 'Errore durante l\'unione dei PDF.', buttons: [ButtonNames.OK] });
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
onClose();
|
|
125
|
-
};
|
|
126
|
-
// ---- Render della sezione configurazione (solo PDF file name + warning) ----
|
|
127
|
-
const configSection = (_jsxs("div", { style: {
|
|
128
|
-
position: 'relative',
|
|
129
|
-
border: `1px solid ${TMColors.border_normal}`,
|
|
130
|
-
borderRadius: '8px',
|
|
131
|
-
padding: '8px',
|
|
132
|
-
height: showTMRelationViewer ? '100%' : undefined,
|
|
133
|
-
flex: showTMRelationViewer ? undefined : 1,
|
|
134
|
-
minHeight: 0,
|
|
135
|
-
marginTop: showTMRelationViewer ? '10px' : undefined,
|
|
136
|
-
display: 'flex',
|
|
137
|
-
flexDirection: 'column',
|
|
138
|
-
boxSizing: 'border-box'
|
|
139
|
-
}, children: [_jsx("span", { style: getFloatingLabelStyle(), title: "Parametri di configurazione (Unisci in PDF)", children: "Parametri di configurazione" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px', overflowY: 'auto', flex: 1 }, children: [_jsx(TMTextBox, { label: "Nome file PDF", value: pdfFileName, validationItems: pdfValidationItems, autoComplete: "one-time-code", placeHolder: "merged.pdf", onValueChanged: (e) => setPdfFileName(e.target.value) }), (!hasEnoughPdfForMerge || hasNonPdfSelected) && (_jsxs("div", { style: {
|
|
140
|
-
display: 'flex',
|
|
141
|
-
flexDirection: 'column',
|
|
142
|
-
gap: '6px',
|
|
143
|
-
padding: '8px 12px',
|
|
144
|
-
border: '1px solid #f0c36d',
|
|
145
|
-
borderRadius: '5px',
|
|
146
|
-
backgroundColor: '#fdf5e2',
|
|
147
|
-
color: '#7a5d00',
|
|
148
|
-
fontSize: '0.85rem'
|
|
149
|
-
}, children: [_jsx("strong", { children: "Attenzione" }), _jsxs("ul", { style: { margin: 0, paddingLeft: '18px', display: 'flex', flexDirection: 'column', gap: '4px' }, children: [!hasEnoughPdfForMerge && (_jsx("li", { children: pdfSelectedCount === 0
|
|
150
|
-
? `Nessun PDF tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.`
|
|
151
|
-
: `Solo 1 PDF tra i selezionati: ne servono almeno ${MIN_PDF_FOR_MERGE}.` })), hasNonPdfSelected && (_jsx("li", { children: (() => {
|
|
152
|
-
const extSet = Array.from(new Set(nonPdfSelectedItems.map(i => (i.ext ?? '').toString().trim().toLowerCase().replace(/^\./, '')).filter(e => e.length > 0)));
|
|
153
|
-
const extLabel = extSet.length > 0
|
|
154
|
-
? ` (${extSet.map(e => '.' + e).join(', ')})`
|
|
155
|
-
: '';
|
|
156
|
-
return nonPdfSelectedItems.length === 1
|
|
157
|
-
? `Un documento non è in formato PDF${extLabel} e sarà escluso dall'unione.`
|
|
158
|
-
: `${nonPdfSelectedItems.length} documenti non sono in formato PDF${extLabel} e saranno esclusi dall'unione.`;
|
|
159
|
-
})() }))] })] }))] })] }));
|
|
160
|
-
return (_jsx(TMModal, { width: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : '480px', showTMRelationViewer ? '90%' : '480px', '95%'), height: calcResponsiveSizes(deviceType, showTMRelationViewer ? '90%' : 'auto', showTMRelationViewer ? '90%' : 'auto', showTMRelationViewer ? '95%' : 'auto'), title: getTitle(), onClose: onClose, showCloseButton: true, children: _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsxs("div", { onContextMenu: (e) => e.preventDefault(), style: { display: 'flex', flexDirection: 'column', gap: '16px', padding: '16px', width: '100%', height: '100%', boxSizing: 'border-box', overflow: 'hidden' }, children: [showTMRelationViewer ? (_jsx("div", { style: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }, children: _jsxs(TMSplitterLayout, { direction: 'vertical', showSeparator: true, separatorSize: 8, separatorColor: 'transparent', separatorActiveColor: 'transparent', overflow: 'visible', min: SPLITTER_MIN, start: SPLITTER_START_65_35, children: [_jsx(TMDownloadRelationViewerSection, { selectedDcmtInfos: selectedDcmtInfos, onSelectionChanged: setSelectedItemsRelationViewer }), configSection] }, "TMMergeToPdf-relation-config") })) : (configSection), _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '12px', flexShrink: 0 }, children: _jsx(TMButton, { caption: pdfSelectedCount === 0 ? 'Unisci in PDF' : `Unisci ${pdfSelectedCount} file in PDF`, icon: _jsx(IconPlay, {}), color: 'success', showTooltip: false, disabled: !isFormValid()
|
|
161
|
-
|| (showTMRelationViewer && selectedItemsRelationViewer.filter(i => i.isDcmt).length === 0)
|
|
162
|
-
|| !hasEnoughPdfForMerge, onClick: run }) })] }) }) }));
|
|
163
|
-
};
|
|
164
|
-
export default TMMergeToPdfForm;
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { DcmtInfo } from '../../../ts';
|
|
3
|
-
import { DocumentDownloadSettings, FileNamingMode } from '../../../helper';
|
|
4
|
-
import { IRelatedDcmt } from './TMMasterDetailDcmts';
|
|
5
|
-
export declare const SPLITTER_MIN: string[];
|
|
6
|
-
export declare const SPLITTER_START_HALF: string[];
|
|
7
|
-
export declare const SPLITTER_START_65_35: string[];
|
|
8
|
-
/** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
|
|
9
|
-
export declare const MIN_PDF_FOR_MERGE = 2;
|
|
10
|
-
/** Stile per le etichette "floating" posizionate sopra i bordi dei container */
|
|
11
|
-
export declare const getFloatingLabelStyle: () => React.CSSProperties;
|
|
12
|
-
/** Chiave univoca per un IRelatedDcmt basata sulla coppia tid+did */
|
|
13
|
-
export declare const getDcmtKey: (item: IRelatedDcmt) => string;
|
|
14
|
-
/** Deduplica gli IRelatedDcmt in base alla coppia tid+did (mantiene la prima occorrenza) */
|
|
15
|
-
export declare const dedupeByTidDid: (items: ReadonlyArray<IRelatedDcmt>) => Array<IRelatedDcmt>;
|
|
16
|
-
/** Verifica se showDirectoryPicker è supportato (Chrome, Edge) */
|
|
17
|
-
export declare const isDirectoryPickerSupported: () => boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf".
|
|
20
|
-
*/
|
|
21
|
-
export declare const isPdfExt: (ext: string | null | undefined) => boolean;
|
|
22
|
-
/** Sanitizza il nome file per Windows (rimuove caratteri illegali e limita la lunghezza) */
|
|
23
|
-
export declare const sanitizeFileName: (fileName: string, fallbackName: string, maxLength?: number) => string;
|
|
24
|
-
/** Verifica se un file esiste nella cartella (FileSystemDirectoryHandle) */
|
|
25
|
-
export declare const fileExists: (dirHandle: FileSystemDirectoryHandle, fileName: string) => Promise<boolean>;
|
|
26
|
-
/** Genera un nome file univoco aggiungendo un suffisso numerico se già esistente */
|
|
27
|
-
export declare const generateUniqueFileName: (dirHandle: FileSystemDirectoryHandle, originalName: string) => Promise<string>;
|
|
28
|
-
/** Recupera il nome leggibile del tipo documento (cache) */
|
|
29
|
-
export declare const getTypeName: (tid: number | undefined) => Promise<string>;
|
|
30
|
-
/** Formatta un valore convertendo le date in formato dd-MM-yyyy [HH-mm-ss] */
|
|
31
|
-
export declare const formatMetadataValue: (value: string) => string;
|
|
32
|
-
/** Recupera i metadati filtrati (primi 5 con mid > 100 e valore presente), concatenati con separatorChar */
|
|
33
|
-
export declare const getFilteredMetadata: (tid: number, did: number, separatorChar: string) => Promise<string | null>;
|
|
34
|
-
/** Opzioni di naming necessarie per generare il nome del file di destinazione */
|
|
35
|
-
export interface IFileNamingOptions {
|
|
36
|
-
fileNamingMode: FileNamingMode;
|
|
37
|
-
separatorChar: string;
|
|
38
|
-
}
|
|
39
|
-
/** Genera il nome file di destinazione in base alle impostazioni di naming */
|
|
40
|
-
export declare const generateTargetFileName: (file: File, dcmtInfo: DcmtInfo, options: IFileNamingOptions) => Promise<string>;
|
|
41
|
-
/**
|
|
42
|
-
* Restituisce i documenti da scaricare:
|
|
43
|
-
* - se è visibile il TMRelationViewer, usa gli isDcmt selezionati al suo interno
|
|
44
|
-
* - altrimenti restituisce i selectedDcmtInfos passati come prop
|
|
45
|
-
*/
|
|
46
|
-
export declare const getDcmtInfosToDownload: (selectedDcmtInfos: Array<DcmtInfo>, selectedItemsRelationViewer: Array<IRelatedDcmt>, showTMRelationViewer: boolean) => Array<DcmtInfo>;
|
|
47
|
-
/**
|
|
48
|
-
* Costruisce lo stato iniziale di DocumentDownloadSettings combinando:
|
|
49
|
-
* - i valori salvati in userSettings (se presenti)
|
|
50
|
-
* - i default della classe
|
|
51
|
-
* Nota: destinationFolder e zipPassword vengono sempre resettati per sicurezza.
|
|
52
|
-
*/
|
|
53
|
-
export declare const buildInitialDownloadSettings: (saved: DocumentDownloadSettings | undefined, defaultInvoiceFormat: DocumentDownloadSettings["invoiceFormat"], defaultOrderFormat: DocumentDownloadSettings["orderFormat"]) => DocumentDownloadSettings;
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { DcmtTypeListCacheService, LayoutModes, SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
2
|
-
import { searchResultToMetadataValues, DocumentDownloadSettings } from '../../../helper';
|
|
3
|
-
import { TMColors } from '../../../utils/theme';
|
|
4
|
-
// ============================================================
|
|
5
|
-
// Costanti condivise tra TMCopyToFolderForm e TMMergeToPdfForm
|
|
6
|
-
// ============================================================
|
|
7
|
-
export const SPLITTER_MIN = ['50', '50'];
|
|
8
|
-
export const SPLITTER_START_HALF = ['50%', '50%'];
|
|
9
|
-
export const SPLITTER_START_65_35 = ['65%', '35%'];
|
|
10
|
-
/** Numero minimo di file PDF necessari per poterli unire in un unico documento. */
|
|
11
|
-
export const MIN_PDF_FOR_MERGE = 2;
|
|
12
|
-
// ============================================================
|
|
13
|
-
// Stili comuni
|
|
14
|
-
// ============================================================
|
|
15
|
-
/** Stile per le etichette "floating" posizionate sopra i bordi dei container */
|
|
16
|
-
export const getFloatingLabelStyle = () => ({
|
|
17
|
-
position: 'absolute',
|
|
18
|
-
top: '-10px',
|
|
19
|
-
left: '12px',
|
|
20
|
-
maxWidth: 'calc(100% - 24px)',
|
|
21
|
-
fontSize: '0.85rem',
|
|
22
|
-
fontWeight: 600,
|
|
23
|
-
color: TMColors.primary,
|
|
24
|
-
padding: '0 8px',
|
|
25
|
-
backgroundColor: 'white',
|
|
26
|
-
zIndex: 1,
|
|
27
|
-
whiteSpace: 'nowrap',
|
|
28
|
-
overflow: 'hidden',
|
|
29
|
-
textOverflow: 'ellipsis',
|
|
30
|
-
display: 'inline-block',
|
|
31
|
-
width: 'fit-content',
|
|
32
|
-
lineHeight: '20px',
|
|
33
|
-
letterSpacing: '0.2px',
|
|
34
|
-
boxSizing: 'border-box'
|
|
35
|
-
});
|
|
36
|
-
// ============================================================
|
|
37
|
-
// Helper su IRelatedDcmt
|
|
38
|
-
// ============================================================
|
|
39
|
-
/** Chiave univoca per un IRelatedDcmt basata sulla coppia tid+did */
|
|
40
|
-
export const getDcmtKey = (item) => `${item.tid ?? ''}_${item.did ?? ''}`;
|
|
41
|
-
/** Deduplica gli IRelatedDcmt in base alla coppia tid+did (mantiene la prima occorrenza) */
|
|
42
|
-
export const dedupeByTidDid = (items) => {
|
|
43
|
-
const map = new Map();
|
|
44
|
-
for (const item of items) {
|
|
45
|
-
const key = getDcmtKey(item);
|
|
46
|
-
if (!map.has(key))
|
|
47
|
-
map.set(key, item);
|
|
48
|
-
}
|
|
49
|
-
return Array.from(map.values());
|
|
50
|
-
};
|
|
51
|
-
// ============================================================
|
|
52
|
-
// Feature detection / Estensioni file
|
|
53
|
-
// ============================================================
|
|
54
|
-
/** Verifica se showDirectoryPicker è supportato (Chrome, Edge) */
|
|
55
|
-
export const isDirectoryPickerSupported = () => {
|
|
56
|
-
return 'showDirectoryPicker' in window;
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf".
|
|
60
|
-
*/
|
|
61
|
-
export const isPdfExt = (ext) => {
|
|
62
|
-
if (!ext)
|
|
63
|
-
return false;
|
|
64
|
-
const normalized = ext.trim().toLowerCase().replace(/^\./, '');
|
|
65
|
-
return normalized === 'pdf';
|
|
66
|
-
};
|
|
67
|
-
// ============================================================
|
|
68
|
-
// Sanitizzazione e gestione nomi file
|
|
69
|
-
// ============================================================
|
|
70
|
-
/** Sanitizza il nome file per Windows (rimuove caratteri illegali e limita la lunghezza) */
|
|
71
|
-
export const sanitizeFileName = (fileName, fallbackName, maxLength = 255) => {
|
|
72
|
-
try {
|
|
73
|
-
const illegalCharsRegex = /[<>:"/\\|?*]/g;
|
|
74
|
-
const controlCharsRegex = /[\x00-\x1F\x7F]/g;
|
|
75
|
-
let sanitized = fileName
|
|
76
|
-
.replace(illegalCharsRegex, '_')
|
|
77
|
-
.replace(controlCharsRegex, '')
|
|
78
|
-
.trim();
|
|
79
|
-
sanitized = sanitized.replace(/[. ]+$/, '');
|
|
80
|
-
if (sanitized.length > maxLength) {
|
|
81
|
-
const lastDotIndex = sanitized.lastIndexOf('.');
|
|
82
|
-
if (lastDotIndex > 0) {
|
|
83
|
-
const extension = sanitized.substring(lastDotIndex);
|
|
84
|
-
const baseName = sanitized.substring(0, lastDotIndex);
|
|
85
|
-
const maxBaseLength = maxLength - extension.length;
|
|
86
|
-
sanitized = baseName.substring(0, maxBaseLength) + extension;
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
sanitized = sanitized.substring(0, maxLength);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return sanitized || fallbackName;
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return fallbackName;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
/** Verifica se un file esiste nella cartella (FileSystemDirectoryHandle) */
|
|
99
|
-
export const fileExists = async (dirHandle, fileName) => {
|
|
100
|
-
try {
|
|
101
|
-
await dirHandle.getFileHandle(fileName, { create: false });
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
/** Genera un nome file univoco aggiungendo un suffisso numerico se già esistente */
|
|
109
|
-
export const generateUniqueFileName = async (dirHandle, originalName) => {
|
|
110
|
-
const splitName = (name) => {
|
|
111
|
-
const lastDotIndex = name.lastIndexOf('.');
|
|
112
|
-
const baseName = lastDotIndex > 0 ? name.substring(0, lastDotIndex) : name;
|
|
113
|
-
const extension = lastDotIndex > 0 ? name.substring(lastDotIndex) : '';
|
|
114
|
-
return { baseName, extension };
|
|
115
|
-
};
|
|
116
|
-
try {
|
|
117
|
-
const { baseName, extension } = splitName(originalName);
|
|
118
|
-
const MAX_ATTEMPTS = 1000;
|
|
119
|
-
for (let counter = 1; counter <= MAX_ATTEMPTS; counter++) {
|
|
120
|
-
const candidateName = counter === 1 ? originalName : `${baseName} (${counter - 1})${extension}`;
|
|
121
|
-
try {
|
|
122
|
-
await dirHandle.getFileHandle(candidateName, { create: false });
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
return candidateName;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return `${baseName}_${Date.now()}${extension}`;
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
const { baseName, extension } = splitName(originalName);
|
|
132
|
-
return `${baseName}_${Date.now()}${extension}`;
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
// ============================================================
|
|
136
|
-
// Helper per la generazione del nome di destinazione del file
|
|
137
|
-
// (in base alle impostazioni utente: tipo, metadati, separatore...)
|
|
138
|
-
// ============================================================
|
|
139
|
-
/** Recupera il nome leggibile del tipo documento (cache) */
|
|
140
|
-
export const getTypeName = async (tid) => {
|
|
141
|
-
const typeList = await DcmtTypeListCacheService.GetAllWithoutMetadataAsync();
|
|
142
|
-
const foundDtd = typeList.find(dtd => dtd.id?.toString() === tid?.toString());
|
|
143
|
-
return foundDtd?.name ?? String(tid);
|
|
144
|
-
};
|
|
145
|
-
/** Formatta un valore convertendo le date in formato dd-MM-yyyy [HH-mm-ss] */
|
|
146
|
-
export const formatMetadataValue = (value) => {
|
|
147
|
-
const date = new Date(value);
|
|
148
|
-
if (!isNaN(date.getTime())) {
|
|
149
|
-
const day = date.getDate().toString().padStart(2, '0');
|
|
150
|
-
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
151
|
-
const year = date.getFullYear();
|
|
152
|
-
const hours = date.getHours();
|
|
153
|
-
const minutes = date.getMinutes();
|
|
154
|
-
const seconds = date.getSeconds();
|
|
155
|
-
if (hours !== 0 || minutes !== 0 || seconds !== 0) {
|
|
156
|
-
const hh = hours.toString().padStart(2, '0');
|
|
157
|
-
const mm = minutes.toString().padStart(2, '0');
|
|
158
|
-
const ss = seconds.toString().padStart(2, '0');
|
|
159
|
-
return `${day}-${month}-${year} ${hh}-${mm}-${ss}`;
|
|
160
|
-
}
|
|
161
|
-
return `${day}-${month}-${year}`;
|
|
162
|
-
}
|
|
163
|
-
return value;
|
|
164
|
-
};
|
|
165
|
-
/** Recupera i metadati filtrati (primi 5 con mid > 100 e valore presente), concatenati con separatorChar */
|
|
166
|
-
export const getFilteredMetadata = async (tid, did, separatorChar) => {
|
|
167
|
-
const metadata = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(tid, did, true);
|
|
168
|
-
if (!metadata)
|
|
169
|
-
return null;
|
|
170
|
-
const dtdResult = metadata.dtdResult;
|
|
171
|
-
const rows = dtdResult?.rows?.[0] ?? [];
|
|
172
|
-
const mids = metadata.selectMIDs;
|
|
173
|
-
const dtdWithMetadata = await DcmtTypeListCacheService.GetWithNotGrantedAsync(tid, did, metadata);
|
|
174
|
-
const mdList = dtdWithMetadata?.metadata ?? [];
|
|
175
|
-
const metadataList = searchResultToMetadataValues(tid, dtdResult, rows, mids, mdList, LayoutModes.Update);
|
|
176
|
-
return metadataList
|
|
177
|
-
.reduce((acc, md) => acc.length < 5 && md.mid && md.mid > 100 && md.value ? [...acc, formatMetadataValue(md.value)] : acc, [])
|
|
178
|
-
.join(separatorChar);
|
|
179
|
-
};
|
|
180
|
-
/** Genera il nome file di destinazione in base alle impostazioni di naming */
|
|
181
|
-
export const generateTargetFileName = async (file, dcmtInfo, options) => {
|
|
182
|
-
const { fileNamingMode, separatorChar } = options;
|
|
183
|
-
const lastDotIndex = file.name.lastIndexOf('.');
|
|
184
|
-
const fileExtension = lastDotIndex > 0 ? file.name.substring(lastDotIndex) : '';
|
|
185
|
-
const fallbackName = dcmtInfo.DID + fileExtension;
|
|
186
|
-
let targetFileName = file.name;
|
|
187
|
-
switch (fileNamingMode) {
|
|
188
|
-
case 'onlyDid':
|
|
189
|
-
targetFileName = fallbackName;
|
|
190
|
-
break;
|
|
191
|
-
case 'documentTypeAndDid': {
|
|
192
|
-
const typeName = await getTypeName(dcmtInfo.TID);
|
|
193
|
-
targetFileName = `${typeName}${separatorChar}${dcmtInfo.DID}${fileExtension}`;
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
case 'documentTypeAndCustomMetadata':
|
|
197
|
-
case 'onlyCustomMetadata': {
|
|
198
|
-
try {
|
|
199
|
-
const filteredMetadata = await getFilteredMetadata(dcmtInfo.TID, dcmtInfo.DID, separatorChar);
|
|
200
|
-
if (filteredMetadata) {
|
|
201
|
-
if (fileNamingMode === 'documentTypeAndCustomMetadata') {
|
|
202
|
-
const typeName = await getTypeName(dcmtInfo.TID);
|
|
203
|
-
targetFileName = `${typeName}${separatorChar}${filteredMetadata}${fileExtension}`;
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
targetFileName = `${filteredMetadata}${fileExtension}`;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
targetFileName = fallbackName;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
catch {
|
|
214
|
-
targetFileName = fallbackName;
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
default:
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
return sanitizeFileName(targetFileName, fallbackName);
|
|
222
|
-
};
|
|
223
|
-
// ============================================================
|
|
224
|
-
// Build della lista di DcmtInfo effettivi da scaricare
|
|
225
|
-
// ============================================================
|
|
226
|
-
/**
|
|
227
|
-
* Restituisce i documenti da scaricare:
|
|
228
|
-
* - se è visibile il TMRelationViewer, usa gli isDcmt selezionati al suo interno
|
|
229
|
-
* - altrimenti restituisce i selectedDcmtInfos passati come prop
|
|
230
|
-
*/
|
|
231
|
-
export const getDcmtInfosToDownload = (selectedDcmtInfos, selectedItemsRelationViewer, showTMRelationViewer) => {
|
|
232
|
-
if (showTMRelationViewer) {
|
|
233
|
-
return selectedItemsRelationViewer
|
|
234
|
-
.filter(i => i.isDcmt && i.tid != null && i.did != null)
|
|
235
|
-
.map(i => ({ TID: i.tid, DID: i.did }));
|
|
236
|
-
}
|
|
237
|
-
return selectedDcmtInfos;
|
|
238
|
-
};
|
|
239
|
-
// ============================================================
|
|
240
|
-
// Stato iniziale settings (con valori salvati o default)
|
|
241
|
-
// ============================================================
|
|
242
|
-
/**
|
|
243
|
-
* Costruisce lo stato iniziale di DocumentDownloadSettings combinando:
|
|
244
|
-
* - i valori salvati in userSettings (se presenti)
|
|
245
|
-
* - i default della classe
|
|
246
|
-
* Nota: destinationFolder e zipPassword vengono sempre resettati per sicurezza.
|
|
247
|
-
*/
|
|
248
|
-
export const buildInitialDownloadSettings = (saved, defaultInvoiceFormat, defaultOrderFormat) => {
|
|
249
|
-
const defaults = new DocumentDownloadSettings();
|
|
250
|
-
return {
|
|
251
|
-
exportMode: saved?.exportMode ?? defaults.exportMode,
|
|
252
|
-
destinationFolder: 'Download',
|
|
253
|
-
zipFileName: saved?.zipFileName ?? defaults.zipFileName,
|
|
254
|
-
zipPassword: '',
|
|
255
|
-
fileNamingMode: saved?.fileNamingMode ?? defaults.fileNamingMode,
|
|
256
|
-
separatorChar: saved?.separatorChar ?? defaults.separatorChar,
|
|
257
|
-
invoiceFormat: saved?.invoiceFormat ?? defaultInvoiceFormat,
|
|
258
|
-
orderFormat: saved?.orderFormat ?? defaultOrderFormat,
|
|
259
|
-
fileExistsMode: saved?.fileExistsMode ?? defaults.fileExistsMode,
|
|
260
|
-
removeSignature: saved?.removeSignature ?? defaults.removeSignature,
|
|
261
|
-
pdfFileName: saved?.pdfFileName ?? defaults.pdfFileName,
|
|
262
|
-
};
|
|
263
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/** File da aggiungere allo ZIP */
|
|
2
|
-
export interface ZipFileEntry {
|
|
3
|
-
/** Nome/percorso nello ZIP (es. "docs/file.txt") */
|
|
4
|
-
filename: string;
|
|
5
|
-
/** Contenuto: string, File, Blob, ArrayBuffer o Uint8Array */
|
|
6
|
-
data: File | Blob | string | ArrayBuffer | Uint8Array;
|
|
7
|
-
/** Commento opzionale */
|
|
8
|
-
comment?: string;
|
|
9
|
-
/** Data modifica (default: ora) */
|
|
10
|
-
lastModDate?: Date;
|
|
11
|
-
}
|
|
12
|
-
/** Opzioni creazione ZIP */
|
|
13
|
-
export interface ZipCreateOptions {
|
|
14
|
-
/** Password AES (opzionale) */
|
|
15
|
-
password?: string;
|
|
16
|
-
/** Compressione 0-9 (default: 6) */
|
|
17
|
-
compressionLevel?: number;
|
|
18
|
-
/** Cifratura: 1=128bit, 2=192bit, 3=256bit (default: 3) */
|
|
19
|
-
encryptionStrength?: 1 | 2 | 3;
|
|
20
|
-
/** Commento globale ZIP */
|
|
21
|
-
comment?: string;
|
|
22
|
-
/** Callback progresso: (indice, totale, nomeFile) */
|
|
23
|
-
onProgress?: (index: number, total: number, filename: string) => void;
|
|
24
|
-
/** Callback progresso singolo file: (bytesElaborati, bytesTotali) */
|
|
25
|
-
onEntryProgress?: (progress: number, total: number) => void;
|
|
26
|
-
/** AbortSignal per annullare */
|
|
27
|
-
signal?: AbortSignal;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Utility per creare file ZIP con password opzionale (AES-256).
|
|
31
|
-
* Tutti i metodi sono statici.
|
|
32
|
-
*/
|
|
33
|
-
export declare class ZipManager {
|
|
34
|
-
/** Configura zip.js (useWebWorkers, maxWorkers) */
|
|
35
|
-
static configure(options: {
|
|
36
|
-
useWebWorkers?: boolean;
|
|
37
|
-
maxWorkers?: number;
|
|
38
|
-
}): void;
|
|
39
|
-
/** Crea ZIP da array di file */
|
|
40
|
-
static createZip(files: ZipFileEntry[], options?: ZipCreateOptions): Promise<Blob>;
|
|
41
|
-
/** Crea ZIP da singolo file */
|
|
42
|
-
static createZipFromFile(filename: string, data: File | Blob | string | ArrayBuffer | Uint8Array, options?: ZipCreateOptions): Promise<Blob>;
|
|
43
|
-
/** Crea ZIP da oggetto { nomeFile: contenuto } */
|
|
44
|
-
static createZipFromMap(filesMap: Record<string, File | Blob | string | ArrayBuffer | Uint8Array>, options?: ZipCreateOptions): Promise<Blob>;
|
|
45
|
-
/** Crea ZIP e avvia download */
|
|
46
|
-
static createAndDownload(files: ZipFileEntry[], downloadFilename: string, options?: ZipCreateOptions): Promise<void>;
|
|
47
|
-
/** Scarica un Blob come file */
|
|
48
|
-
static downloadBlob(blob: Blob, filename: string): void;
|
|
49
|
-
/** Crea URL temporaneo per Blob (ricordarsi revokeObjectURL!) */
|
|
50
|
-
static createObjectURL(blob: Blob): string;
|
|
51
|
-
/** Rilascia URL creato con createObjectURL */
|
|
52
|
-
static revokeObjectURL(url: string): void;
|
|
53
|
-
/** Converte data nel reader appropriato per zip.js */
|
|
54
|
-
private static createReader;
|
|
55
|
-
}
|
|
56
|
-
export default ZipManager;
|
package/lib/helper/ZipManager.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { BlobReader, BlobWriter, TextReader, Uint8ArrayReader, ZipWriter, configure } from "@zip.js/zip.js";
|
|
2
|
-
// ============================================================================
|
|
3
|
-
// ZIP MANAGER CLASS
|
|
4
|
-
// ============================================================================
|
|
5
|
-
/**
|
|
6
|
-
* Utility per creare file ZIP con password opzionale (AES-256).
|
|
7
|
-
* Tutti i metodi sono statici.
|
|
8
|
-
*/
|
|
9
|
-
export class ZipManager {
|
|
10
|
-
/** Configura zip.js (useWebWorkers, maxWorkers) */
|
|
11
|
-
static configure(options) {
|
|
12
|
-
configure(options);
|
|
13
|
-
}
|
|
14
|
-
// ========================================================================
|
|
15
|
-
// CREAZIONE ZIP
|
|
16
|
-
// ========================================================================
|
|
17
|
-
/** Crea ZIP da array di file */
|
|
18
|
-
static async createZip(files, options = {}) {
|
|
19
|
-
const { password, compressionLevel = 6, encryptionStrength = 3, comment, onProgress, onEntryProgress, signal } = options;
|
|
20
|
-
// Validazione password: stringa vuota = nessuna cifratura
|
|
21
|
-
const usePassword = typeof password === "string" && password.length > 0 ? password : undefined;
|
|
22
|
-
const blobWriter = new BlobWriter("application/zip");
|
|
23
|
-
const zipWriter = new ZipWriter(blobWriter, { password: usePassword, zipCrypto: true });
|
|
24
|
-
try {
|
|
25
|
-
const total = files.length;
|
|
26
|
-
for (let i = 0; i < files.length; i++) {
|
|
27
|
-
if (signal?.aborted) {
|
|
28
|
-
throw new DOMException("Operazione annullata", "AbortError");
|
|
29
|
-
}
|
|
30
|
-
const file = files[i];
|
|
31
|
-
onProgress?.(i + 1, total, file.filename);
|
|
32
|
-
const reader = this.createReader(file.data);
|
|
33
|
-
await zipWriter.add(file.filename, reader, {
|
|
34
|
-
comment: file.comment,
|
|
35
|
-
lastModDate: file.lastModDate,
|
|
36
|
-
signal,
|
|
37
|
-
password: usePassword,
|
|
38
|
-
encryptionStrength,
|
|
39
|
-
onprogress: onEntryProgress ? (progress, total) => onEntryProgress(progress, total) : undefined
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
const commentBytes = comment ? new TextEncoder().encode(comment) : undefined;
|
|
43
|
-
return await zipWriter.close(commentBytes);
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
try {
|
|
47
|
-
await zipWriter.close();
|
|
48
|
-
}
|
|
49
|
-
catch { /* ignora */ }
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/** Crea ZIP da singolo file */
|
|
54
|
-
static async createZipFromFile(filename, data, options = {}) {
|
|
55
|
-
return this.createZip([{ filename, data }], options);
|
|
56
|
-
}
|
|
57
|
-
/** Crea ZIP da oggetto { nomeFile: contenuto } */
|
|
58
|
-
static async createZipFromMap(filesMap, options = {}) {
|
|
59
|
-
const files = Object.entries(filesMap).map(([filename, data]) => ({ filename, data }));
|
|
60
|
-
return this.createZip(files, options);
|
|
61
|
-
}
|
|
62
|
-
// ========================================================================
|
|
63
|
-
// DOWNLOAD
|
|
64
|
-
// ========================================================================
|
|
65
|
-
/** Crea ZIP e avvia download */
|
|
66
|
-
static async createAndDownload(files, downloadFilename, options = {}) {
|
|
67
|
-
const blob = await this.createZip(files, options);
|
|
68
|
-
this.downloadBlob(blob, downloadFilename);
|
|
69
|
-
}
|
|
70
|
-
/** Scarica un Blob come file */
|
|
71
|
-
static downloadBlob(blob, filename) {
|
|
72
|
-
const url = URL.createObjectURL(blob);
|
|
73
|
-
const link = document.createElement("a");
|
|
74
|
-
link.href = url;
|
|
75
|
-
link.download = filename;
|
|
76
|
-
link.style.display = "none";
|
|
77
|
-
document.body.appendChild(link);
|
|
78
|
-
link.click();
|
|
79
|
-
document.body.removeChild(link);
|
|
80
|
-
setTimeout(() => URL.revokeObjectURL(url), 100);
|
|
81
|
-
}
|
|
82
|
-
/** Crea URL temporaneo per Blob (ricordarsi revokeObjectURL!) */
|
|
83
|
-
static createObjectURL(blob) {
|
|
84
|
-
return URL.createObjectURL(blob);
|
|
85
|
-
}
|
|
86
|
-
/** Rilascia URL creato con createObjectURL */
|
|
87
|
-
static revokeObjectURL(url) {
|
|
88
|
-
URL.revokeObjectURL(url);
|
|
89
|
-
}
|
|
90
|
-
// ========================================================================
|
|
91
|
-
// PRIVATE
|
|
92
|
-
// ========================================================================
|
|
93
|
-
/** Converte data nel reader appropriato per zip.js */
|
|
94
|
-
static createReader(data) {
|
|
95
|
-
if (typeof data === "string")
|
|
96
|
-
return new TextReader(data);
|
|
97
|
-
if (data instanceof Uint8Array)
|
|
98
|
-
return new Uint8ArrayReader(data);
|
|
99
|
-
if (data instanceof ArrayBuffer)
|
|
100
|
-
return new Uint8ArrayReader(new Uint8Array(data));
|
|
101
|
-
return new BlobReader(data);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
export default ZipManager;
|