@acorex/core 21.0.2-next.24 → 21.0.2-next.26
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/fesm2022/acorex-core-components.mjs +3 -3
- package/fesm2022/acorex-core-components.mjs.map +1 -1
- package/fesm2022/acorex-core-config.mjs +3 -3
- package/fesm2022/acorex-core-config.mjs.map +1 -1
- package/fesm2022/acorex-core-constants.mjs.map +1 -1
- package/fesm2022/acorex-core-date-time.mjs +25 -25
- package/fesm2022/acorex-core-date-time.mjs.map +1 -1
- package/fesm2022/acorex-core-events.mjs +3 -3
- package/fesm2022/acorex-core-events.mjs.map +1 -1
- package/fesm2022/acorex-core-file.mjs +92 -685
- package/fesm2022/acorex-core-file.mjs.map +1 -1
- package/fesm2022/acorex-core-format.mjs +19 -19
- package/fesm2022/acorex-core-format.mjs.map +1 -1
- package/fesm2022/acorex-core-full-screen.mjs +3 -3
- package/fesm2022/acorex-core-full-screen.mjs.map +1 -1
- package/fesm2022/acorex-core-icon.mjs +3 -3
- package/fesm2022/acorex-core-icon.mjs.map +1 -1
- package/fesm2022/acorex-core-image.mjs +3 -3
- package/fesm2022/acorex-core-image.mjs.map +1 -1
- package/fesm2022/acorex-core-locale.mjs +10 -10
- package/fesm2022/acorex-core-locale.mjs.map +1 -1
- package/fesm2022/acorex-core-memoize.mjs.map +1 -1
- package/fesm2022/acorex-core-network.mjs +3 -3
- package/fesm2022/acorex-core-network.mjs.map +1 -1
- package/fesm2022/acorex-core-pipes.mjs +3 -3
- package/fesm2022/acorex-core-pipes.mjs.map +1 -1
- package/fesm2022/acorex-core-platform.mjs +4 -4
- package/fesm2022/acorex-core-platform.mjs.map +1 -1
- package/fesm2022/acorex-core-storage.mjs +9 -9
- package/fesm2022/acorex-core-storage.mjs.map +1 -1
- package/fesm2022/acorex-core-translation.mjs +16 -16
- package/fesm2022/acorex-core-translation.mjs.map +1 -1
- package/fesm2022/acorex-core-utils.mjs +6 -4
- package/fesm2022/acorex-core-utils.mjs.map +1 -1
- package/fesm2022/acorex-core-validation.mjs +40 -40
- package/fesm2022/acorex-core-validation.mjs.map +1 -1
- package/fesm2022/acorex-core-z-index.mjs +3 -3
- package/fesm2022/acorex-core-z-index.mjs.map +1 -1
- package/fesm2022/acorex-core.mjs.map +1 -1
- package/package.json +23 -23
- package/types/acorex-core-file.d.ts +85 -0
- package/{format/index.d.ts → types/acorex-core-format.d.ts} +2 -2
- package/{utils/index.d.ts → types/acorex-core-utils.d.ts} +10 -2
- package/{validation/index.d.ts → types/acorex-core-validation.d.ts} +10 -10
- package/file/index.d.ts +0 -321
- /package/{components/index.d.ts → types/acorex-core-components.d.ts} +0 -0
- /package/{config/index.d.ts → types/acorex-core-config.d.ts} +0 -0
- /package/{constants/index.d.ts → types/acorex-core-constants.d.ts} +0 -0
- /package/{date-time/index.d.ts → types/acorex-core-date-time.d.ts} +0 -0
- /package/{events/index.d.ts → types/acorex-core-events.d.ts} +0 -0
- /package/{full-screen/index.d.ts → types/acorex-core-full-screen.d.ts} +0 -0
- /package/{icon/index.d.ts → types/acorex-core-icon.d.ts} +0 -0
- /package/{image/index.d.ts → types/acorex-core-image.d.ts} +0 -0
- /package/{locale/index.d.ts → types/acorex-core-locale.d.ts} +0 -0
- /package/{memoize/index.d.ts → types/acorex-core-memoize.d.ts} +0 -0
- /package/{network/index.d.ts → types/acorex-core-network.d.ts} +0 -0
- /package/{pipes/index.d.ts → types/acorex-core-pipes.d.ts} +0 -0
- /package/{platform/index.d.ts → types/acorex-core-platform.d.ts} +0 -0
- /package/{storage/index.d.ts → types/acorex-core-storage.d.ts} +0 -0
- /package/{translation/index.d.ts → types/acorex-core-translation.d.ts} +0 -0
- /package/{z-index/index.d.ts → types/acorex-core-z-index.d.ts} +0 -0
- /package/{index.d.ts → types/acorex-core.d.ts} +0 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable,
|
|
3
|
-
import * as i2 from '@acorex/core/validation';
|
|
4
|
-
import { AXValidationService, AXValidationRegistryService, AXValidationModule } from '@acorex/core/validation';
|
|
2
|
+
import { Injectable, NgModule, inject, DOCUMENT, PLATFORM_ID } from '@angular/core';
|
|
5
3
|
import * as i1 from '@acorex/core/format';
|
|
6
4
|
import { AXFormatModule } from '@acorex/core/format';
|
|
7
5
|
|
|
@@ -31,603 +29,24 @@ class AXFileSizeFormatter {
|
|
|
31
29
|
const i = Math.floor(Math.log(size) / Math.log(k));
|
|
32
30
|
return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
33
31
|
}
|
|
34
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
35
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
32
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
33
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter }); }
|
|
36
34
|
}
|
|
37
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
35
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileSizeFormatter, decorators: [{
|
|
38
36
|
type: Injectable
|
|
39
37
|
}] });
|
|
40
38
|
|
|
41
|
-
/** Human-readable file size (binary units, e.g. `41.5 MB`). */
|
|
42
|
-
function formatFileSizeBytes(bytes) {
|
|
43
|
-
if (!Number.isFinite(bytes) || bytes < 0) {
|
|
44
|
-
return '0 B';
|
|
45
|
-
}
|
|
46
|
-
if (bytes === 0) {
|
|
47
|
-
return '0 B';
|
|
48
|
-
}
|
|
49
|
-
const k = 1024;
|
|
50
|
-
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
51
|
-
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), units.length - 1);
|
|
52
|
-
const value = bytes / Math.pow(k, i);
|
|
53
|
-
if (i === 0) {
|
|
54
|
-
return `${bytes} B`;
|
|
55
|
-
}
|
|
56
|
-
const digits = value >= 100 ? 0 : value >= 10 ? 1 : 2;
|
|
57
|
-
return `${value.toFixed(digits)} ${units[i]}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Well-known utility keys (optional per {@link AXFileType}). */
|
|
61
|
-
const AX_FILE_TYPE_UTILITY = {
|
|
62
|
-
preview: 'preview',
|
|
63
|
-
duration: 'duration',
|
|
64
|
-
formatSize: 'formatSize',
|
|
65
|
-
formatDuration: 'formatDuration',
|
|
66
|
-
createLocalPreviewUrl: 'createLocalPreviewUrl',
|
|
67
|
-
/** Resolves catalog name for mixed file-picker rows. */
|
|
68
|
-
pickerCatalog: 'pickerCatalog',
|
|
69
|
-
};
|
|
70
|
-
function createFileTypeUtilitiesContext(readAsDataUrl, platformId) {
|
|
71
|
-
return { readAsDataUrl, platformId };
|
|
72
|
-
}
|
|
73
|
-
function hasFileTypeUtility(fileType, name) {
|
|
74
|
-
return typeof fileType?.utilities?.[name] === 'function';
|
|
75
|
-
}
|
|
76
|
-
async function runFileTypeUtility(fileType, name, ctx, ...args) {
|
|
77
|
-
const fn = fileType?.utilities?.[name];
|
|
78
|
-
if (!fn) {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
return (await fn(ctx, ...args));
|
|
82
|
-
}
|
|
83
|
-
function runFileTypeUtilitySync(fileType, name, ctx, ...args) {
|
|
84
|
-
const fn = fileType?.utilities?.[name];
|
|
85
|
-
if (!fn) {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
return fn(ctx, ...args);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Contributes {@link AXFileType} entries (multi provider). */
|
|
92
|
-
class AXFileTypeInfoProvider {
|
|
93
|
-
}
|
|
94
|
-
const AX_FILE_TYPE_INFO_PROVIDER = new InjectionToken('AX_FILE_TYPE_INFO_PROVIDER');
|
|
95
|
-
function provideFileTypeInfoProvider(provider) {
|
|
96
|
-
return {
|
|
97
|
-
provide: AX_FILE_TYPE_INFO_PROVIDER,
|
|
98
|
-
useClass: provider,
|
|
99
|
-
multi: true,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Merges type-level validations with extension overrides (extension wins per field). */
|
|
104
|
-
function mergeFileValidations(base, override) {
|
|
105
|
-
if (!override) {
|
|
106
|
-
return { ...base };
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
mimeTypes: override.mimeTypes ?? base.mimeTypes,
|
|
110
|
-
minSize: override.minSize ?? base.minSize,
|
|
111
|
-
maxSize: override.maxSize ?? base.maxSize,
|
|
112
|
-
rules: override.rules ?? base.rules,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/** Resolved validations for a type + optional extension. */
|
|
116
|
-
function resolveFileValidations(type, extension) {
|
|
117
|
-
return mergeFileValidations(type.validations ?? {}, extension?.validations);
|
|
118
|
-
}
|
|
119
|
-
/** True when no mime/size/rules are defined on the type. */
|
|
120
|
-
function isEmptyFileValidations(validations) {
|
|
121
|
-
if (!validations) {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
return ((validations.mimeTypes?.length ?? 0) === 0 &&
|
|
125
|
-
validations.minSize == null &&
|
|
126
|
-
validations.maxSize == null &&
|
|
127
|
-
(validations.rules?.length ?? 0) === 0);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Extension-only mode: empty type `validations` and a non-empty `extensions` list.
|
|
131
|
-
* Files must match a listed extension; rules come from that extension entry.
|
|
132
|
-
*/
|
|
133
|
-
function isExtensionsOnlyType(type) {
|
|
134
|
-
return isEmptyFileValidations(type.validations) && (type.extensions?.length ?? 0) > 0;
|
|
135
|
-
}
|
|
136
|
-
/** File extension from name (lowercase, no dot). */
|
|
137
|
-
function getFileExtension(fileName) {
|
|
138
|
-
const parts = fileName.trim().split('.');
|
|
139
|
-
return parts.length > 1 ? (parts.pop()?.toLowerCase() ?? '') : '';
|
|
140
|
-
}
|
|
141
|
-
/** Matching extension entry for a file within a type, if any. */
|
|
142
|
-
function findFileTypeExtension(file, type) {
|
|
143
|
-
const ext = getFileExtension(file.name);
|
|
144
|
-
if (!ext || !type.extensions?.length) {
|
|
145
|
-
return undefined;
|
|
146
|
-
}
|
|
147
|
-
return type.extensions.find((e) => e.name.toLowerCase() === ext);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** Maps {@link AXFileValidations} to executable validation entries. */
|
|
151
|
-
function fileValidationsToRules(validations) {
|
|
152
|
-
const rules = [];
|
|
153
|
-
if (validations.mimeTypes?.length) {
|
|
154
|
-
rules.push({
|
|
155
|
-
rule: 'fileMimeType',
|
|
156
|
-
options: { allowed: validations.mimeTypes },
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
if (validations.minSize != null) {
|
|
160
|
-
rules.push({
|
|
161
|
-
rule: 'fileMinSize',
|
|
162
|
-
options: { minSize: validations.minSize },
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
if (validations.maxSize != null) {
|
|
166
|
-
rules.push({
|
|
167
|
-
rule: 'fileMaxSize',
|
|
168
|
-
options: { maxSize: validations.maxSize },
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
if (validations.rules?.length) {
|
|
172
|
-
rules.push(...validations.rules);
|
|
173
|
-
}
|
|
174
|
-
return rules;
|
|
175
|
-
}
|
|
176
|
-
/** Failed validation results; empty array means the file is valid. */
|
|
177
|
-
async function validateFileWithValidations(validation, file, validations) {
|
|
178
|
-
const entries = fileValidationsToRules(validations);
|
|
179
|
-
const errors = [];
|
|
180
|
-
for (const { rule, options } of entries) {
|
|
181
|
-
const result = await validation.validate(rule, file, options);
|
|
182
|
-
if (!result.result) {
|
|
183
|
-
errors.push(result);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return errors;
|
|
187
|
-
}
|
|
188
|
-
/** Validates a file against a type; extension rules override when the file name matches. */
|
|
189
|
-
async function validateFileAgainstType(validation, file, type, extension) {
|
|
190
|
-
const matchedExtension = extension ?? findFileTypeExtension(file, type);
|
|
191
|
-
if (isExtensionsOnlyType(type) && !matchedExtension) {
|
|
192
|
-
const ext = getFileExtension(file.name);
|
|
193
|
-
return [
|
|
194
|
-
{
|
|
195
|
-
rule: 'fileExtension',
|
|
196
|
-
result: false,
|
|
197
|
-
message: ext ? `Extension ".${ext}" is not allowed.` : 'File must have an allowed extension.',
|
|
198
|
-
value: ext,
|
|
199
|
-
},
|
|
200
|
-
];
|
|
201
|
-
}
|
|
202
|
-
const resolved = resolveFileValidations(type, matchedExtension);
|
|
203
|
-
return validateFileWithValidations(validation, file, resolved);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
class AXFileTypeRegistryService {
|
|
207
|
-
constructor() {
|
|
208
|
-
this.validation = inject(AXValidationService);
|
|
209
|
-
this.providers = inject(AX_FILE_TYPE_INFO_PROVIDER, { optional: true }) ?? [];
|
|
210
|
-
this.registeredTypes = [];
|
|
211
|
-
this.cache = null;
|
|
212
|
-
}
|
|
213
|
-
/** Registers or replaces catalog entries (e.g. from feature bootstrap). */
|
|
214
|
-
registerTypes(types) {
|
|
215
|
-
for (const type of types) {
|
|
216
|
-
const index = this.registeredTypes.findIndex((t) => t.name === type.name);
|
|
217
|
-
if (index >= 0) {
|
|
218
|
-
this.registeredTypes[index] = type;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
this.registeredTypes.push(type);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
this.invalidateCache();
|
|
225
|
-
}
|
|
226
|
-
invalidateCache() {
|
|
227
|
-
this.cache = null;
|
|
228
|
-
}
|
|
229
|
-
async resolveTypes() {
|
|
230
|
-
if (this.cache) {
|
|
231
|
-
return this.cache;
|
|
232
|
-
}
|
|
233
|
-
const byName = new Map();
|
|
234
|
-
if (this.providers.length) {
|
|
235
|
-
const batches = await Promise.all(this.providers.map((p) => p.items()));
|
|
236
|
-
for (const batch of batches) {
|
|
237
|
-
for (const type of batch) {
|
|
238
|
-
if (!byName.has(type.name)) {
|
|
239
|
-
byName.set(type.name, type);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
for (const type of this.registeredTypes) {
|
|
245
|
-
byName.set(type.name, type);
|
|
246
|
-
}
|
|
247
|
-
this.cache = [...byName.values()];
|
|
248
|
-
return this.cache;
|
|
249
|
-
}
|
|
250
|
-
async getTypes() {
|
|
251
|
-
return this.resolveTypes();
|
|
252
|
-
}
|
|
253
|
-
async get(name) {
|
|
254
|
-
const types = await this.resolveTypes();
|
|
255
|
-
return types.find((t) => t.name === name);
|
|
256
|
-
}
|
|
257
|
-
async accept(typeNames) {
|
|
258
|
-
const names = typeNames ? (Array.isArray(typeNames) ? typeNames : [typeNames]) : undefined;
|
|
259
|
-
const types = await this.resolveTypes();
|
|
260
|
-
const selected = names?.length ? types.filter((t) => names.includes(t.name)) : types;
|
|
261
|
-
if (names?.length && selected.length === 0) {
|
|
262
|
-
return '';
|
|
263
|
-
}
|
|
264
|
-
const parts = new Set();
|
|
265
|
-
for (const type of selected) {
|
|
266
|
-
type.validations?.mimeTypes?.forEach((m) => parts.add(m));
|
|
267
|
-
type.extensions?.forEach((ext) => {
|
|
268
|
-
ext.validations?.mimeTypes?.forEach((m) => parts.add(m));
|
|
269
|
-
parts.add(`.${ext.name.replace(/^\./, '')}`);
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
return [...parts].join(',');
|
|
273
|
-
}
|
|
274
|
-
async matchType(file) {
|
|
275
|
-
const types = await this.resolveTypes();
|
|
276
|
-
const mime = file.type.trim().toLowerCase();
|
|
277
|
-
return types.find((type) => {
|
|
278
|
-
const patterns = [
|
|
279
|
-
...(type.validations?.mimeTypes ?? []),
|
|
280
|
-
...(type.extensions?.flatMap((e) => e.validations?.mimeTypes ?? []) ?? []),
|
|
281
|
-
];
|
|
282
|
-
if (!patterns.length) {
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
return patterns.some((pattern) => this.matchesMime(mime, pattern.trim().toLowerCase()));
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
async validate(file, typeName) {
|
|
289
|
-
const type = await this.get(typeName);
|
|
290
|
-
if (!type) {
|
|
291
|
-
return [
|
|
292
|
-
{
|
|
293
|
-
rule: 'fileType',
|
|
294
|
-
result: false,
|
|
295
|
-
message: `Unknown file type: ${typeName}`,
|
|
296
|
-
value: typeName,
|
|
297
|
-
},
|
|
298
|
-
];
|
|
299
|
-
}
|
|
300
|
-
const extension = findFileTypeExtension(file, type);
|
|
301
|
-
return validateFileAgainstType(this.validation, file, type, extension);
|
|
302
|
-
}
|
|
303
|
-
async validateAgainstTypes(file, typeNames) {
|
|
304
|
-
const names = Array.isArray(typeNames) ? typeNames : [typeNames];
|
|
305
|
-
let lastErrors = [];
|
|
306
|
-
for (const name of names) {
|
|
307
|
-
const errors = await this.validate(file, name);
|
|
308
|
-
if (errors.length === 0) {
|
|
309
|
-
return [];
|
|
310
|
-
}
|
|
311
|
-
lastErrors = errors;
|
|
312
|
-
}
|
|
313
|
-
return lastErrors;
|
|
314
|
-
}
|
|
315
|
-
async validateMany(files, typeNames) {
|
|
316
|
-
const accepted = [];
|
|
317
|
-
const rejected = [];
|
|
318
|
-
for (const file of files) {
|
|
319
|
-
const errors = await this.validateAgainstTypes(file, typeNames);
|
|
320
|
-
if (errors.length === 0) {
|
|
321
|
-
accepted.push(file);
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
rejected.push({ file, errors });
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return { accepted, rejected };
|
|
328
|
-
}
|
|
329
|
-
matchesMime(mime, pattern) {
|
|
330
|
-
if (!pattern || pattern === '*/*' || pattern === '*') {
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
if (pattern.endsWith('/*')) {
|
|
334
|
-
const category = pattern.slice(0, -2);
|
|
335
|
-
return mime.startsWith(`${category}/`) || (mime === '' && category === 'application');
|
|
336
|
-
}
|
|
337
|
-
return mime === pattern;
|
|
338
|
-
}
|
|
339
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
340
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, providedIn: 'root' }); }
|
|
341
|
-
}
|
|
342
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileTypeRegistryService, decorators: [{
|
|
343
|
-
type: Injectable,
|
|
344
|
-
args: [{ providedIn: 'root' }]
|
|
345
|
-
}] });
|
|
346
|
-
|
|
347
|
-
const MB$4 = 1024 * 1024;
|
|
348
|
-
const AX_AUDIO_FILE_TYPE = {
|
|
349
|
-
name: 'audio',
|
|
350
|
-
title: 'Audio',
|
|
351
|
-
icon: 'fa-light fa-music ax-text-amber-500',
|
|
352
|
-
validations: {
|
|
353
|
-
mimeTypes: ['audio/*'],
|
|
354
|
-
minSize: 1,
|
|
355
|
-
maxSize: 50 * MB$4,
|
|
356
|
-
},
|
|
357
|
-
extensions: [
|
|
358
|
-
{ name: 'mp3', title: 'MP3' },
|
|
359
|
-
{ name: 'wav', title: 'WAV', validations: { maxSize: 30 * MB$4 } },
|
|
360
|
-
{ name: 'ogg', title: 'OGG' },
|
|
361
|
-
{ name: 'm4a', title: 'M4A' },
|
|
362
|
-
],
|
|
363
|
-
};
|
|
364
|
-
class AXAudioFileTypeProvider extends AXFileTypeInfoProvider {
|
|
365
|
-
items() {
|
|
366
|
-
return Promise.resolve([AX_AUDIO_FILE_TYPE]);
|
|
367
|
-
}
|
|
368
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
369
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider }); }
|
|
370
|
-
}
|
|
371
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXAudioFileTypeProvider, decorators: [{
|
|
372
|
-
type: Injectable
|
|
373
|
-
}] });
|
|
374
|
-
|
|
375
|
-
const MB$3 = 1024 * 1024;
|
|
376
|
-
/** Extension-only: no type `validations` — only listed extensions are allowed. */
|
|
377
|
-
const AX_DOCUMENT_FILE_TYPE = {
|
|
378
|
-
name: 'document',
|
|
379
|
-
title: 'Document',
|
|
380
|
-
icon: 'fa-light fa-file-lines ax-text-red-500',
|
|
381
|
-
extensions: [{ name: 'pdf', title: 'PDF', validations: { mimeTypes: ['application/pdf'], maxSize: 5 * MB$3 } }],
|
|
382
|
-
};
|
|
383
|
-
class AXDocumentFileTypeProvider extends AXFileTypeInfoProvider {
|
|
384
|
-
items() {
|
|
385
|
-
return Promise.resolve([AX_DOCUMENT_FILE_TYPE]);
|
|
386
|
-
}
|
|
387
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
388
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider }); }
|
|
389
|
-
}
|
|
390
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXDocumentFileTypeProvider, decorators: [{
|
|
391
|
-
type: Injectable
|
|
392
|
-
}] });
|
|
393
|
-
|
|
394
|
-
const MB$2 = 1024 * 1024;
|
|
395
|
-
const AX_FILE_FILE_TYPE = {
|
|
396
|
-
name: 'file',
|
|
397
|
-
title: 'File',
|
|
398
|
-
icon: 'fa-light fa-file ax-text-neutral-500',
|
|
399
|
-
validations: {
|
|
400
|
-
mimeTypes: ['application/*', 'text/*'],
|
|
401
|
-
minSize: 1,
|
|
402
|
-
maxSize: 100 * MB$2,
|
|
403
|
-
},
|
|
404
|
-
extensions: [
|
|
405
|
-
{ name: 'pdf', title: 'PDF', validations: { mimeTypes: ['application/pdf'], maxSize: 25 * MB$2 } },
|
|
406
|
-
{ name: 'doc', title: 'Word' },
|
|
407
|
-
{ name: 'docx', title: 'Word' },
|
|
408
|
-
{ name: 'txt', title: 'Text', validations: { mimeTypes: ['text/plain'], maxSize: 5 * MB$2 } },
|
|
409
|
-
{ name: 'zip', title: 'ZIP', validations: { maxSize: 50 * MB$2 } },
|
|
410
|
-
],
|
|
411
|
-
};
|
|
412
|
-
class AXFileFileTypeProvider extends AXFileTypeInfoProvider {
|
|
413
|
-
items() {
|
|
414
|
-
return Promise.resolve([AX_FILE_FILE_TYPE]);
|
|
415
|
-
}
|
|
416
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
417
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider }); }
|
|
418
|
-
}
|
|
419
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileFileTypeProvider, decorators: [{
|
|
420
|
-
type: Injectable
|
|
421
|
-
}] });
|
|
422
|
-
|
|
423
|
-
const MB$1 = 1024 * 1024;
|
|
424
|
-
const AX_IMAGE_FILE_TYPE = {
|
|
425
|
-
name: 'image',
|
|
426
|
-
title: 'Image',
|
|
427
|
-
icon: 'fa-light fa-image ax-text-purple-500',
|
|
428
|
-
validations: {
|
|
429
|
-
mimeTypes: ['image/*'],
|
|
430
|
-
minSize: 1,
|
|
431
|
-
maxSize: 100 * MB$1,
|
|
432
|
-
},
|
|
433
|
-
extensions: [
|
|
434
|
-
{ name: 'jpg', title: 'JPEG' },
|
|
435
|
-
{ name: 'jpeg', title: 'JPEG', validations: { maxSize: 5 * MB$1 } },
|
|
436
|
-
{ name: 'png', title: 'PNG' },
|
|
437
|
-
{ name: 'gif', title: 'GIF' },
|
|
438
|
-
{ name: 'webp', title: 'WebP' },
|
|
439
|
-
{ name: 'svg', title: 'SVG', validations: { maxSize: 2 * MB$1 } },
|
|
440
|
-
],
|
|
441
|
-
};
|
|
442
|
-
class AXImageFileTypeProvider extends AXFileTypeInfoProvider {
|
|
443
|
-
items() {
|
|
444
|
-
return Promise.resolve([AX_IMAGE_FILE_TYPE]);
|
|
445
|
-
}
|
|
446
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
447
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider }); }
|
|
448
|
-
}
|
|
449
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXImageFileTypeProvider, decorators: [{
|
|
450
|
-
type: Injectable
|
|
451
|
-
}] });
|
|
452
|
-
|
|
453
|
-
const MB = 1024 * 1024;
|
|
454
|
-
const AX_VIDEO_FILE_TYPE = {
|
|
455
|
-
name: 'video',
|
|
456
|
-
title: 'Video',
|
|
457
|
-
icon: 'fa-light fa-video ax-text-blue-500',
|
|
458
|
-
validations: {
|
|
459
|
-
mimeTypes: ['video/*'],
|
|
460
|
-
minSize: 1,
|
|
461
|
-
maxSize: 500 * MB,
|
|
462
|
-
},
|
|
463
|
-
extensions: [
|
|
464
|
-
{ name: 'mp4', title: 'MP4' },
|
|
465
|
-
{ name: 'webm', title: 'WebM', validations: { maxSize: 200 * MB } },
|
|
466
|
-
{ name: 'ogg', title: 'OGG' },
|
|
467
|
-
],
|
|
468
|
-
};
|
|
469
|
-
class AXVideoFileTypeProvider extends AXFileTypeInfoProvider {
|
|
470
|
-
items() {
|
|
471
|
-
return Promise.resolve([AX_VIDEO_FILE_TYPE]);
|
|
472
|
-
}
|
|
473
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
474
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider }); }
|
|
475
|
-
}
|
|
476
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXVideoFileTypeProvider, decorators: [{
|
|
477
|
-
type: Injectable
|
|
478
|
-
}] });
|
|
479
|
-
|
|
480
|
-
/** Built-in file type provider classes (one logical type per provider). */
|
|
481
|
-
const AX_BUILTIN_FILE_TYPE_PROVIDERS = [
|
|
482
|
-
AXImageFileTypeProvider,
|
|
483
|
-
AXVideoFileTypeProvider,
|
|
484
|
-
AXAudioFileTypeProvider,
|
|
485
|
-
AXFileFileTypeProvider,
|
|
486
|
-
AXDocumentFileTypeProvider,
|
|
487
|
-
];
|
|
488
|
-
/** Registers all built-in file type providers (image, video, audio, file, document). */
|
|
489
|
-
function provideBuiltinFileTypeProviders() {
|
|
490
|
-
return AX_BUILTIN_FILE_TYPE_PROVIDERS.map((provider) => provideFileTypeInfoProvider(provider));
|
|
491
|
-
}
|
|
492
|
-
/** @deprecated Use {@link provideBuiltinFileTypeProviders}. */
|
|
493
|
-
const provideDefaultFileTypeProviders = provideBuiltinFileTypeProviders;
|
|
494
|
-
|
|
495
|
-
class AXFileMimeTypeValidationRule {
|
|
496
|
-
get name() {
|
|
497
|
-
return 'fileMimeType';
|
|
498
|
-
}
|
|
499
|
-
async validate(value, options) {
|
|
500
|
-
const mime = (value instanceof File || value instanceof Blob ? value.type : '').trim().toLowerCase();
|
|
501
|
-
const allowed = options.allowed ?? [];
|
|
502
|
-
const valid = allowed.length === 0 ||
|
|
503
|
-
allowed.some((pattern) => this.matchesMime(mime, pattern.trim().toLowerCase()));
|
|
504
|
-
return {
|
|
505
|
-
rule: this.name,
|
|
506
|
-
result: valid,
|
|
507
|
-
message: valid ? '' : (options.message ?? 'File type is not allowed.'),
|
|
508
|
-
value: mime,
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
matchesMime(mime, pattern) {
|
|
512
|
-
if (!pattern || pattern === '*/*' || pattern === '*') {
|
|
513
|
-
return true;
|
|
514
|
-
}
|
|
515
|
-
if (pattern.endsWith('/*')) {
|
|
516
|
-
const category = pattern.slice(0, -2);
|
|
517
|
-
return mime.startsWith(`${category}/`) || (mime === '' && category === 'application');
|
|
518
|
-
}
|
|
519
|
-
return mime === pattern;
|
|
520
|
-
}
|
|
521
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
522
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule }); }
|
|
523
|
-
}
|
|
524
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMimeTypeValidationRule, decorators: [{
|
|
525
|
-
type: Injectable
|
|
526
|
-
}] });
|
|
527
|
-
|
|
528
|
-
class AXFileMinSizeValidationRule {
|
|
529
|
-
get name() {
|
|
530
|
-
return 'fileMinSize';
|
|
531
|
-
}
|
|
532
|
-
async validate(value, options) {
|
|
533
|
-
const size = value instanceof File || value instanceof Blob ? value.size : 0;
|
|
534
|
-
const valid = size >= options.minSize;
|
|
535
|
-
const limitLabel = formatFileSizeBytes(options.minSize);
|
|
536
|
-
return {
|
|
537
|
-
rule: this.name,
|
|
538
|
-
result: valid,
|
|
539
|
-
message: valid
|
|
540
|
-
? ''
|
|
541
|
-
: (options.message ?? `File is too small. Minimum size is ${limitLabel}.`),
|
|
542
|
-
value: size,
|
|
543
|
-
minSize: options.minSize,
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
547
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule }); }
|
|
548
|
-
}
|
|
549
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMinSizeValidationRule, decorators: [{
|
|
550
|
-
type: Injectable
|
|
551
|
-
}] });
|
|
552
|
-
|
|
553
|
-
class AXFileMaxSizeValidationRule {
|
|
554
|
-
get name() {
|
|
555
|
-
return 'fileMaxSize';
|
|
556
|
-
}
|
|
557
|
-
async validate(value, options) {
|
|
558
|
-
const size = value instanceof File || value instanceof Blob ? value.size : 0;
|
|
559
|
-
const valid = size <= options.maxSize;
|
|
560
|
-
const limitLabel = formatFileSizeBytes(options.maxSize);
|
|
561
|
-
return {
|
|
562
|
-
rule: this.name,
|
|
563
|
-
result: valid,
|
|
564
|
-
message: valid
|
|
565
|
-
? ''
|
|
566
|
-
: (options.message ??
|
|
567
|
-
`File is too large. Maximum size is ${limitLabel}.`),
|
|
568
|
-
value: size,
|
|
569
|
-
maxSize: options.maxSize,
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
573
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule }); }
|
|
574
|
-
}
|
|
575
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileMaxSizeValidationRule, decorators: [{
|
|
576
|
-
type: Injectable
|
|
577
|
-
}] });
|
|
578
|
-
|
|
579
|
-
/** Validation rule classes to register with {@link AXValidationModule}. */
|
|
580
|
-
const AX_FILE_VALIDATION_RULES = [
|
|
581
|
-
AXFileMimeTypeValidationRule,
|
|
582
|
-
AXFileMinSizeValidationRule,
|
|
583
|
-
AXFileMaxSizeValidationRule,
|
|
584
|
-
];
|
|
585
|
-
/** Registers file validation rules with {@link AXValidationRegistryService}. */
|
|
586
|
-
function provideFileValidationRules() {
|
|
587
|
-
return {
|
|
588
|
-
provide: 'AXValidationModuleFactory',
|
|
589
|
-
useFactory: (registry) => () => {
|
|
590
|
-
registry.register(...AX_FILE_VALIDATION_RULES);
|
|
591
|
-
},
|
|
592
|
-
deps: [AXValidationRegistryService],
|
|
593
|
-
multi: true,
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Registers validation rules and optional built-in file type providers.
|
|
598
|
-
* {@link AXFileTypeRegistryService} and {@link AXFileService} are `providedIn: 'root'`.
|
|
599
|
-
*/
|
|
600
|
-
function provideFileTypeSystem() {
|
|
601
|
-
return [provideFileValidationRules(), ...provideBuiltinFileTypeProviders()];
|
|
602
|
-
}
|
|
603
|
-
|
|
604
39
|
class AXFileModule {
|
|
605
|
-
static
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
ngModule: AXFileModule,
|
|
609
|
-
providers: [
|
|
610
|
-
provideFileValidationRules(),
|
|
611
|
-
...(includeDefaults ? provideDefaultFileTypeProviders() : []),
|
|
612
|
-
...(config?.fileTypeProviders ?? []),
|
|
613
|
-
],
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
static forChild(config) {
|
|
617
|
-
return AXFileModule.forRoot(config);
|
|
618
|
-
}
|
|
619
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
620
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, imports: [i1.AXFormatModule, i2.AXValidationModule] }); }
|
|
621
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileModule, providers: [AXFileSizeFormatter], imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] }),
|
|
622
|
-
AXValidationModule.forChild({ rules: [...AX_FILE_VALIDATION_RULES] })] }); }
|
|
40
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
41
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, imports: [i1.AXFormatModule] }); }
|
|
42
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, providers: [AXFileSizeFormatter], imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] })] }); }
|
|
623
43
|
}
|
|
624
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
44
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileModule, decorators: [{
|
|
625
45
|
type: NgModule,
|
|
626
46
|
args: [{
|
|
627
|
-
imports: [
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
],
|
|
47
|
+
imports: [AXFormatModule.forChild({ formatters: [AXFileSizeFormatter] })],
|
|
48
|
+
exports: [],
|
|
49
|
+
declarations: [],
|
|
631
50
|
providers: [AXFileSizeFormatter],
|
|
632
51
|
}]
|
|
633
52
|
}] });
|
|
@@ -635,124 +54,112 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
|
|
|
635
54
|
class AXFileService {
|
|
636
55
|
constructor() {
|
|
637
56
|
this.document = inject(DOCUMENT);
|
|
638
|
-
this.
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
57
|
+
this.platformID = inject(PLATFORM_ID);
|
|
58
|
+
/**
|
|
59
|
+
* Gets the size of a file, blob, or base64 string.
|
|
60
|
+
*
|
|
61
|
+
* @param file - The file, blob, or base64 string to get size for
|
|
62
|
+
* @returns number | false - The size in bytes or false if not a base64 string
|
|
63
|
+
*/
|
|
64
|
+
this.blobToBase64 = (blob) => {
|
|
65
|
+
if (blob instanceof Blob) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const reader = new FileReader();
|
|
68
|
+
reader.onerror = reject;
|
|
69
|
+
reader.onload = () => {
|
|
70
|
+
resolve(reader.result);
|
|
71
|
+
};
|
|
72
|
+
reader.readAsDataURL(blob);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return Promise.reject('input is not blob');
|
|
77
|
+
}
|
|
78
|
+
};
|
|
657
79
|
}
|
|
658
80
|
/**
|
|
659
|
-
* Opens a file selection dialog.
|
|
660
|
-
*
|
|
661
|
-
*
|
|
81
|
+
* Opens a file selection dialog and returns the selected files.
|
|
82
|
+
*
|
|
83
|
+
* @param options - Optional configuration for file selection
|
|
84
|
+
* @param options.accept - File types to accept (e.g., 'image/*', '.pdf')
|
|
85
|
+
* @param options.multiple - Whether to allow multiple file selection
|
|
86
|
+
* @returns Promise<File[]> - Promise that resolves with the selected files
|
|
662
87
|
*/
|
|
663
|
-
|
|
664
|
-
const resolved = await this.resolveChooseOptions(options);
|
|
665
|
-
const files = await this.openFileDialog(resolved);
|
|
666
|
-
if (files.length === 0) {
|
|
667
|
-
return { accepted: [], rejected: [] };
|
|
668
|
-
}
|
|
669
|
-
if (options.fileType) {
|
|
670
|
-
return this.validateMany(files, options.fileType);
|
|
671
|
-
}
|
|
672
|
-
return { accepted: files, rejected: [] };
|
|
673
|
-
}
|
|
674
|
-
async choose(options) {
|
|
675
|
-
const { accepted } = await this.chooseValidated(options);
|
|
676
|
-
return accepted;
|
|
677
|
-
}
|
|
678
|
-
blobToBase64(blob) {
|
|
679
|
-
if (!(blob instanceof Blob)) {
|
|
680
|
-
return Promise.reject(new Error('input is not blob'));
|
|
681
|
-
}
|
|
88
|
+
choose(options) {
|
|
682
89
|
return new Promise((resolve, reject) => {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
90
|
+
options = Object.assign({ multiple: false }, options);
|
|
91
|
+
const input = this.document.createElement('input');
|
|
92
|
+
input.style.display = 'none';
|
|
93
|
+
this.document.body.appendChild(input);
|
|
94
|
+
input.type = 'file';
|
|
95
|
+
input.accept = options.accept || '';
|
|
96
|
+
input.multiple = options.multiple || false;
|
|
97
|
+
//
|
|
98
|
+
const onError = (e) => {
|
|
99
|
+
reject(e);
|
|
100
|
+
this.document.body.removeChild(input);
|
|
101
|
+
input.remove();
|
|
102
|
+
input.removeEventListener('change', onChange);
|
|
103
|
+
input.removeEventListener('error', onError);
|
|
104
|
+
};
|
|
105
|
+
//
|
|
106
|
+
const onChange = () => {
|
|
107
|
+
resolve(Array.from(input.files || []));
|
|
108
|
+
this.document.body.removeChild(input);
|
|
109
|
+
input.remove();
|
|
110
|
+
input.removeEventListener('change', onChange);
|
|
111
|
+
input.removeEventListener('error', onError);
|
|
112
|
+
};
|
|
113
|
+
//
|
|
114
|
+
input.addEventListener('change', onChange);
|
|
115
|
+
input.addEventListener('error', onError);
|
|
116
|
+
input.click();
|
|
687
117
|
});
|
|
688
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Gets the size of a file, blob, or base64 string.
|
|
121
|
+
*
|
|
122
|
+
* @param file - The file, blob, or base64 string to get size for
|
|
123
|
+
* @returns number | false - The size in bytes or false if not a base64 string
|
|
124
|
+
*/
|
|
689
125
|
getSize(file) {
|
|
690
126
|
if (this.isBase64(file)) {
|
|
691
127
|
return this.getBase64Size(file);
|
|
692
128
|
}
|
|
693
129
|
return false;
|
|
694
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Checks if a string is a valid base64 string.
|
|
133
|
+
*
|
|
134
|
+
* @param base64 - The string to check
|
|
135
|
+
* @returns boolean - True if the string is a valid base64 string
|
|
136
|
+
*/
|
|
695
137
|
isBase64(base64) {
|
|
696
138
|
const regx = /[^:]\w+\/[\w-+\d.]+(?=;|,)/;
|
|
697
139
|
return regx.test(base64);
|
|
698
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Gets the size of a base64 string in bytes.
|
|
143
|
+
*
|
|
144
|
+
* @param base64 - The base64 string to get size for
|
|
145
|
+
* @returns number - The size in bytes
|
|
146
|
+
*/
|
|
699
147
|
getBase64Size(base64) {
|
|
700
148
|
return atob(base64.substring(base64.indexOf(',') + 1)).length;
|
|
701
149
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
if (options.fileType) {
|
|
705
|
-
const accept = options.accept ?? (await this.getAcceptAttribute(options.fileType));
|
|
706
|
-
if (isDevMode() && !accept) {
|
|
707
|
-
const name = Array.isArray(options.fileType) ? options.fileType.join(', ') : options.fileType;
|
|
708
|
-
console.warn(`[AXFileService] No accept filter for file type "${name}". ` +
|
|
709
|
-
'Register a file type provider (e.g. provideConversationFileCatalog).');
|
|
710
|
-
}
|
|
711
|
-
return { accept, multiple };
|
|
712
|
-
}
|
|
713
|
-
return { accept: options.accept ?? '', multiple };
|
|
714
|
-
}
|
|
715
|
-
openFileDialog(options) {
|
|
716
|
-
return new Promise((resolve, reject) => {
|
|
717
|
-
const input = this.document.createElement('input');
|
|
718
|
-
input.style.display = 'none';
|
|
719
|
-
this.document.body.appendChild(input);
|
|
720
|
-
input.type = 'file';
|
|
721
|
-
input.accept = options.accept;
|
|
722
|
-
input.multiple = options.multiple;
|
|
723
|
-
const cleanup = () => {
|
|
724
|
-
input.removeEventListener('change', onChange);
|
|
725
|
-
input.removeEventListener('error', onError);
|
|
726
|
-
if (input.parentNode) {
|
|
727
|
-
this.document.body.removeChild(input);
|
|
728
|
-
}
|
|
729
|
-
input.remove();
|
|
730
|
-
};
|
|
731
|
-
const onError = (e) => {
|
|
732
|
-
cleanup();
|
|
733
|
-
reject(e);
|
|
734
|
-
};
|
|
735
|
-
const onChange = () => {
|
|
736
|
-
const files = Array.from(input.files ?? []);
|
|
737
|
-
cleanup();
|
|
738
|
-
resolve(files);
|
|
739
|
-
};
|
|
740
|
-
input.addEventListener('change', onChange);
|
|
741
|
-
input.addEventListener('error', onError);
|
|
742
|
-
input.click();
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
746
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXFileService, providedIn: 'root' }); }
|
|
150
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
151
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, providedIn: 'root' }); }
|
|
747
152
|
}
|
|
748
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
153
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: AXFileService, decorators: [{
|
|
749
154
|
type: Injectable,
|
|
750
|
-
args: [{
|
|
155
|
+
args: [{
|
|
156
|
+
providedIn: 'root',
|
|
157
|
+
}]
|
|
751
158
|
}] });
|
|
752
159
|
|
|
753
160
|
/**
|
|
754
161
|
* Generated bundle index. Do not edit.
|
|
755
162
|
*/
|
|
756
163
|
|
|
757
|
-
export {
|
|
164
|
+
export { AXFileModule, AXFileService, AXFileSizeFormatter };
|
|
758
165
|
//# sourceMappingURL=acorex-core-file.mjs.map
|