@acorex/components 21.0.0-next.19 → 21.0.0-next.20
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-components-dialog.mjs +11 -2
- package/fesm2022/acorex-components-dialog.mjs.map +1 -1
- package/fesm2022/acorex-components-loading-dialog.mjs +11 -2
- package/fesm2022/acorex-components-loading-dialog.mjs.map +1 -1
- package/fesm2022/acorex-components-rrule.mjs +2 -2
- package/fesm2022/acorex-components-rrule.mjs.map +1 -1
- package/fesm2022/acorex-components-scheduler-picker.mjs +2339 -0
- package/fesm2022/acorex-components-scheduler-picker.mjs.map +1 -0
- package/fesm2022/acorex-components-uploader.mjs +13 -611
- package/fesm2022/acorex-components-uploader.mjs.map +1 -1
- package/package.json +11 -7
- package/scheduler-picker/README.md +15 -0
- package/scheduler-picker/index.d.ts +1360 -0
- package/uploader/index.d.ts +4 -331
|
@@ -1,559 +1,12 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, inject, Injectable, ElementRef, ChangeDetectorRef, DOCUMENT, PLATFORM_ID, EventEmitter, HostBinding, Output, Input, Directive, ViewEncapsulation, Component, input, NgModule } from '@angular/core';
|
|
3
|
-
import { AXTranslationService, AXTranslatorPipe, AXTranslationModule } from '@acorex/core/translation';
|
|
4
|
-
import { AXUnsubscriber } from '@acorex/core/utils';
|
|
5
|
-
import { isPlatformBrowser, AsyncPipe, NgClass, CommonModule } from '@angular/common';
|
|
6
|
-
import { AXPopupService, AXPopupModule } from '@acorex/components/popup';
|
|
7
|
-
import { AXFileService, AXFileModule } from '@acorex/core/file';
|
|
8
|
-
import { sumBy } from 'lodash-es';
|
|
9
|
-
import { Subject, BehaviorSubject, map } from 'rxjs';
|
|
10
1
|
import { AXComponent, AXClosableComponent, MXBaseComponent } from '@acorex/cdk/common';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
get name() {
|
|
20
|
-
return this.file.name;
|
|
21
|
-
}
|
|
22
|
-
get ext() {
|
|
23
|
-
const parts = this.name.split('.');
|
|
24
|
-
if (parts.length > 1) {
|
|
25
|
-
return parts[parts.length - 1];
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
// No extension found
|
|
29
|
-
return '';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
get size() {
|
|
33
|
-
return this.file.size;
|
|
34
|
-
}
|
|
35
|
-
get file() {
|
|
36
|
-
return this.uploadFile;
|
|
37
|
-
}
|
|
38
|
-
constructor(uploadFile) {
|
|
39
|
-
this.uploadFile = uploadFile;
|
|
40
|
-
this._progress = signal(0, ...(ngDevMode ? [{ debugName: "_progress" }] : []));
|
|
41
|
-
this.progress = computed(() => this._progress(), ...(ngDevMode ? [{ debugName: "progress" }] : []));
|
|
42
|
-
this._estimateTime = signal(0, ...(ngDevMode ? [{ debugName: "_estimateTime" }] : []));
|
|
43
|
-
this.estimateTime = computed(() => this._estimateTime(), ...(ngDevMode ? [{ debugName: "estimateTime" }] : []));
|
|
44
|
-
this._status = signal('new', ...(ngDevMode ? [{ debugName: "_status" }] : []));
|
|
45
|
-
this.status = computed(() => this._status(), ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
46
|
-
this._message = signal(null, ...(ngDevMode ? [{ debugName: "_message" }] : []));
|
|
47
|
-
this.message = computed(() => this._message(), ...(ngDevMode ? [{ debugName: "message" }] : []));
|
|
48
|
-
this._isDetermined = signal(false, ...(ngDevMode ? [{ debugName: "_isDetermined" }] : []));
|
|
49
|
-
this.isDetermined = computed(() => this._isDetermined(), ...(ngDevMode ? [{ debugName: "isDetermined" }] : []));
|
|
50
|
-
this.bytesTransferred = 0;
|
|
51
|
-
this.onCancel = new Subject();
|
|
52
|
-
this.onStart = new Subject();
|
|
53
|
-
this.onFailed = new Subject();
|
|
54
|
-
this.onComplete = new BehaviorSubject(null);
|
|
55
|
-
}
|
|
56
|
-
estimateTimeRemaining(bytesTransferred) {
|
|
57
|
-
const now = Date.now();
|
|
58
|
-
const elapsed = now - this.startTime; // Time in milliseconds
|
|
59
|
-
if (isNaN(elapsed) || elapsed === 0) {
|
|
60
|
-
return null; // Avoid division by zero
|
|
61
|
-
}
|
|
62
|
-
const speed = (bytesTransferred || 1) / elapsed; // Bytes per millisecond
|
|
63
|
-
const remainingBytes = this.size - bytesTransferred;
|
|
64
|
-
const estimatedTime = Math.ceil(remainingBytes / speed); // Time in milliseconds
|
|
65
|
-
return estimatedTime; // Return the estimated time in milliseconds
|
|
66
|
-
}
|
|
67
|
-
setTransferredBytes(value) {
|
|
68
|
-
this.bytesTransferred = value;
|
|
69
|
-
if (value > 0 && !this._isDetermined() && (this.status() == 'new' || this.status() == 'inprogress')) {
|
|
70
|
-
this._isDetermined.set(true);
|
|
71
|
-
}
|
|
72
|
-
this.updateEstimateTime();
|
|
73
|
-
}
|
|
74
|
-
updateEstimateTime() {
|
|
75
|
-
this._estimateTime.set(this.estimateTimeRemaining(this.bytesTransferred));
|
|
76
|
-
const progress = Math.floor((this.bytesTransferred / this.size) * 100);
|
|
77
|
-
this._progress.set(progress);
|
|
78
|
-
}
|
|
79
|
-
async upload() {
|
|
80
|
-
this.startTime = Date.now();
|
|
81
|
-
this._progress.set(0);
|
|
82
|
-
this._status.set('inprogress');
|
|
83
|
-
this.onStart.next();
|
|
84
|
-
}
|
|
85
|
-
cancel() {
|
|
86
|
-
this._status.set('canceled');
|
|
87
|
-
this.bytesTransferred = 0;
|
|
88
|
-
this._estimateTime.set(0);
|
|
89
|
-
this._progress.set(0);
|
|
90
|
-
this.onCancel.next();
|
|
91
|
-
}
|
|
92
|
-
redo() {
|
|
93
|
-
// this.startTime = Date.now();
|
|
94
|
-
this._progress.set(0);
|
|
95
|
-
this._status.set('inprogress');
|
|
96
|
-
this._message.set(null);
|
|
97
|
-
this.onStart.next();
|
|
98
|
-
}
|
|
99
|
-
error(message) {
|
|
100
|
-
this._status.set('failed');
|
|
101
|
-
this.bytesTransferred = 0;
|
|
102
|
-
this._estimateTime.set(0);
|
|
103
|
-
this._progress.set(0);
|
|
104
|
-
this._message.set(message);
|
|
105
|
-
this.onFailed.next();
|
|
106
|
-
}
|
|
107
|
-
finish(data) {
|
|
108
|
-
this._status.set('completed');
|
|
109
|
-
this.bytesTransferred = this.size;
|
|
110
|
-
this._estimateTime.set(0);
|
|
111
|
-
this._progress.set(100);
|
|
112
|
-
this.onComplete.next(data);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Service for managing file uploads with drag-and-drop support, progress tracking, and dialog management.
|
|
118
|
-
* @category Services
|
|
119
|
-
*/
|
|
120
|
-
class AXUploaderService {
|
|
121
|
-
constructor() {
|
|
122
|
-
/**
|
|
123
|
-
* Popup service for showing upload dialogs.
|
|
124
|
-
* @ignore
|
|
125
|
-
*/
|
|
126
|
-
this.popupService = inject(AXPopupService);
|
|
127
|
-
/**
|
|
128
|
-
* Translation service for localized text.
|
|
129
|
-
* @ignore
|
|
130
|
-
*/
|
|
131
|
-
this.translateService = inject(AXTranslationService);
|
|
132
|
-
/**
|
|
133
|
-
* File service for file operations.
|
|
134
|
-
* @ignore
|
|
135
|
-
*/
|
|
136
|
-
this.fileService = inject(AXFileService);
|
|
137
|
-
/**
|
|
138
|
-
* Behavior subject for managing upload requests.
|
|
139
|
-
* @ignore
|
|
140
|
-
*/
|
|
141
|
-
this._files$ = new BehaviorSubject([]);
|
|
142
|
-
/**
|
|
143
|
-
* Gets the files behavior subject for observing upload requests.
|
|
144
|
-
*/
|
|
145
|
-
this.files = this._files$.asObservable();
|
|
146
|
-
/**
|
|
147
|
-
* Subject for file upload start events.
|
|
148
|
-
*/
|
|
149
|
-
this.onFileUploadStart = new Subject();
|
|
150
|
-
/**
|
|
151
|
-
* Subject for file upload complete events.
|
|
152
|
-
*/
|
|
153
|
-
this.onFileUploadComplete = new Subject();
|
|
154
|
-
/**
|
|
155
|
-
* Subject for all files upload complete events.
|
|
156
|
-
*/
|
|
157
|
-
this.onFilesUploadComplete = new Subject();
|
|
158
|
-
/**
|
|
159
|
-
* Subject for file upload canceled events.
|
|
160
|
-
*/
|
|
161
|
-
this.onFileUploadCanceled = new Subject();
|
|
162
|
-
/**
|
|
163
|
-
* Signal indicating if any upload has determined progress.
|
|
164
|
-
*/
|
|
165
|
-
this.isAnyDetermined = computed(() => this._files$.value.some((file) => file.isDetermined()), ...(ngDevMode ? [{ debugName: "isAnyDetermined" }] : []));
|
|
166
|
-
/**
|
|
167
|
-
* Observable for total estimated upload time.
|
|
168
|
-
*/
|
|
169
|
-
this.totalEstimateTime = this._files$.pipe(map((files) => sumBy(files, (file) => (file.status() === 'inprogress' ? file.estimateTime() : 0))));
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Shows the upload dialog with the list of files.
|
|
173
|
-
* @private
|
|
174
|
-
*/
|
|
175
|
-
async showDialog() {
|
|
176
|
-
const filesCount = this._files$.getValue().length;
|
|
177
|
-
Promise.resolve().then(function () { return uploaderList_component; }).then(async (c) => {
|
|
178
|
-
this.popupService
|
|
179
|
-
.open(c.AXUploaderListComponent, {
|
|
180
|
-
size: 'sm',
|
|
181
|
-
title: filesCount > 1
|
|
182
|
-
? await this.translateService.translateAsync('@acorex:uploader.zone.uploadFiles')
|
|
183
|
-
: await this.translateService.translateAsync('@acorex:uploader.zone.uploadFile'),
|
|
184
|
-
})
|
|
185
|
-
.then(async () => {
|
|
186
|
-
await this.cancelAll();
|
|
187
|
-
this.clearAll();
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Converts a File object to an AXUploadRequest.
|
|
193
|
-
* @private
|
|
194
|
-
*/
|
|
195
|
-
convertFileToRequest(file) {
|
|
196
|
-
return new AXUploadRequest(file);
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Starts uploading files that are in 'new' status.
|
|
200
|
-
* @private
|
|
201
|
-
*/
|
|
202
|
-
async startUpload() {
|
|
203
|
-
const newFiles = this._files$.value.filter((c) => c.status() === 'new');
|
|
204
|
-
for (const file of newFiles) {
|
|
205
|
-
await this.bindEvents(file);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Binds event handlers to an upload request.
|
|
210
|
-
* @private
|
|
211
|
-
*/
|
|
212
|
-
async bindEvents(c) {
|
|
213
|
-
c.onStart.subscribe(() => {
|
|
214
|
-
this.onFileUploadStart.next({
|
|
215
|
-
component: this,
|
|
216
|
-
uploadedFile: c,
|
|
217
|
-
isUserInteraction: false,
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
c.onComplete.subscribe((data) => {
|
|
221
|
-
Object.assign(c, { metaData: data });
|
|
222
|
-
this.onFileUploadComplete.next({
|
|
223
|
-
component: this,
|
|
224
|
-
uploadedFile: c,
|
|
225
|
-
isUserInteraction: false,
|
|
226
|
-
});
|
|
227
|
-
const isAllDone = this._files$.value.every((f) => f.status() === 'completed' || f.status() === 'canceled' || f.status() === 'failed');
|
|
228
|
-
if (isAllDone) {
|
|
229
|
-
this.onFilesUploadComplete.next({
|
|
230
|
-
component: this,
|
|
231
|
-
uploadedFiles: this._files$.value,
|
|
232
|
-
isUserInteraction: false,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
c.onCancel.subscribe(() => {
|
|
237
|
-
this.onFileUploadCanceled.next({
|
|
238
|
-
component: this,
|
|
239
|
-
uploadedFile: c,
|
|
240
|
-
isUserInteraction: false,
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Opens the file browser dialog and returns selected files as upload requests.
|
|
246
|
-
* @param options - Configuration options for file selection
|
|
247
|
-
* @returns Promise that resolves to an array of upload requests
|
|
248
|
-
*/
|
|
249
|
-
async browse(options = { multiple: false }) {
|
|
250
|
-
try {
|
|
251
|
-
const files = await this.fileService.choose({ multiple: options?.multiple || false, accept: options.accept });
|
|
252
|
-
if (files.length) {
|
|
253
|
-
return this.add(files);
|
|
254
|
-
}
|
|
255
|
-
return [];
|
|
256
|
-
}
|
|
257
|
-
catch (error) {
|
|
258
|
-
// It's good practice to log the error.
|
|
259
|
-
console.error('File browse failed:', error);
|
|
260
|
-
return [];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Adds files to the upload queue and starts the upload process.
|
|
265
|
-
* @param files - Files to add to the upload queue
|
|
266
|
-
* @returns Promise that resolves to an array of upload requests
|
|
267
|
-
*/
|
|
268
|
-
async add(files) {
|
|
269
|
-
const list = Array.from(files).map((f) => this.convertFileToRequest(f));
|
|
270
|
-
const newFiles = [...this._files$.value, ...list];
|
|
271
|
-
this._files$.next(newFiles);
|
|
272
|
-
await this.showDialog();
|
|
273
|
-
this.startUpload();
|
|
274
|
-
return list;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Cancels all pending and in-progress uploads.
|
|
278
|
-
*/
|
|
279
|
-
async cancelAll() {
|
|
280
|
-
await Promise.all(this._files$.value.filter((c) => c.status() !== 'completed').map((c) => c.cancel()));
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Clears all completed uploads from the queue.
|
|
284
|
-
*/
|
|
285
|
-
clearAll() {
|
|
286
|
-
const remainingFiles = this._files$.value.filter((c) => c.status() === 'inprogress');
|
|
287
|
-
this._files$.next(remainingFiles);
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Removes a specific upload request from the queue.
|
|
291
|
-
* @param item - The upload request to remove
|
|
292
|
-
*/
|
|
293
|
-
remove(item) {
|
|
294
|
-
const updatedFiles = this._files$.value.filter((c) => c !== item);
|
|
295
|
-
this._files$.next(updatedFiles);
|
|
296
|
-
}
|
|
297
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
298
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderService, providedIn: 'root' }); }
|
|
299
|
-
}
|
|
300
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderService, decorators: [{
|
|
301
|
-
type: Injectable,
|
|
302
|
-
args: [{ providedIn: 'root' }]
|
|
303
|
-
}] });
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* A directive that provides drag-and-drop and file upload functionality.
|
|
307
|
-
* When applied to an element, it enables drag-and-drop file uploads and file browsing.
|
|
308
|
-
* @category Directives
|
|
309
|
-
*/
|
|
310
|
-
class AXUploaderZoneDirective {
|
|
311
|
-
/**
|
|
312
|
-
* Initializes the directive with event listeners and service subscriptions.
|
|
313
|
-
*/
|
|
314
|
-
constructor() {
|
|
315
|
-
/**
|
|
316
|
-
* The element reference for the directive host.
|
|
317
|
-
* @ignore
|
|
318
|
-
*/
|
|
319
|
-
this.elementRef = inject(ElementRef);
|
|
320
|
-
/**
|
|
321
|
-
* Whether multiple files can be selected.
|
|
322
|
-
* @defaultValue true
|
|
323
|
-
*/
|
|
324
|
-
this.multiple = true;
|
|
325
|
-
/**
|
|
326
|
-
* File types that are accepted for upload.
|
|
327
|
-
* @defaultValue null
|
|
328
|
-
*/
|
|
329
|
-
this.accept = null;
|
|
330
|
-
/**
|
|
331
|
-
* Change detector reference.
|
|
332
|
-
* @ignore
|
|
333
|
-
*/
|
|
334
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
335
|
-
/**
|
|
336
|
-
* Document reference.
|
|
337
|
-
* @ignore
|
|
338
|
-
*/
|
|
339
|
-
this.document = inject(DOCUMENT);
|
|
340
|
-
/**
|
|
341
|
-
* Platform ID for browser detection.
|
|
342
|
-
* @ignore
|
|
343
|
-
*/
|
|
344
|
-
this.platformID = inject(PLATFORM_ID);
|
|
345
|
-
/**
|
|
346
|
-
* Upload service instance.
|
|
347
|
-
* @ignore
|
|
348
|
-
*/
|
|
349
|
-
this.uploadService = inject(AXUploaderService);
|
|
350
|
-
/**
|
|
351
|
-
* Unsubscriber service instance.
|
|
352
|
-
* @ignore
|
|
353
|
-
*/
|
|
354
|
-
this.unsubscriber = inject(AXUnsubscriber);
|
|
355
|
-
/**
|
|
356
|
-
* Translation service instance.
|
|
357
|
-
* @ignore
|
|
358
|
-
*/
|
|
359
|
-
this.translateService = inject(AXTranslationService);
|
|
360
|
-
/**
|
|
361
|
-
* Emitted when files are changed (added, removed, etc.).
|
|
362
|
-
*/
|
|
363
|
-
this.onChanged = new EventEmitter();
|
|
364
|
-
/**
|
|
365
|
-
* Emitted when a single file upload is completed.
|
|
366
|
-
*/
|
|
367
|
-
this.onFileUploadComplete = new EventEmitter();
|
|
368
|
-
/**
|
|
369
|
-
* Emitted when all files upload is completed.
|
|
370
|
-
*/
|
|
371
|
-
this.onFilesUploadComplete = new EventEmitter();
|
|
372
|
-
/**
|
|
373
|
-
* CSS class for the overlay state.
|
|
374
|
-
* @ignore
|
|
375
|
-
*/
|
|
376
|
-
this.stateClass = 'ax-uploader-overlay-state';
|
|
377
|
-
this.element = this.elementRef.nativeElement;
|
|
378
|
-
this.element.style.position = 'relative';
|
|
379
|
-
//
|
|
380
|
-
this.uploadService.onFileUploadComplete.pipe(this.unsubscriber.takeUntilDestroy).subscribe((c) => {
|
|
381
|
-
this.onFileUploadComplete.next(c);
|
|
382
|
-
});
|
|
383
|
-
this.uploadService.onFilesUploadComplete.pipe(this.unsubscriber.takeUntilDestroy).subscribe((c) => {
|
|
384
|
-
this.onFilesUploadComplete.next(c);
|
|
385
|
-
});
|
|
386
|
-
//
|
|
387
|
-
setTimeout(() => {
|
|
388
|
-
const browseHandlers = this.element.querySelectorAll('[data-ax-uploader-browse-handle="true"]');
|
|
389
|
-
if (browseHandlers.length <= 0)
|
|
390
|
-
this.element.addEventListener('click', this.browser.bind(this), true);
|
|
391
|
-
});
|
|
392
|
-
this.element.addEventListener('dragenter', this.handleDragEnter.bind(this), true);
|
|
393
|
-
this.element.addEventListener('dragover', this.handleDragOver.bind(this), true);
|
|
394
|
-
this.element.addEventListener('drop', this.handleOnDrop.bind(this), true);
|
|
395
|
-
this.element.addEventListener('dragleave', this.removeZone.bind(this), true);
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Cleans up event listeners when the directive is destroyed.
|
|
399
|
-
*/
|
|
400
|
-
ngOnDestroy() {
|
|
401
|
-
this.element.removeEventListener('click', this.browser.bind(this));
|
|
402
|
-
this.element.removeEventListener('dragenter', this.handleDragEnter.bind(this));
|
|
403
|
-
this.element.removeEventListener('drop', this.handleOnDrop.bind(this));
|
|
404
|
-
this.element.removeEventListener('dragover', this.handleDragOver.bind(this));
|
|
405
|
-
this.element.removeEventListener('dragleave', this.removeZone.bind(this));
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Handles drag enter events to show the upload overlay.
|
|
409
|
-
* @private
|
|
410
|
-
*/
|
|
411
|
-
async handleDragEnter(event) {
|
|
412
|
-
this.createZone();
|
|
413
|
-
event.preventDefault();
|
|
414
|
-
event.stopImmediatePropagation();
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Handles drop events to process dropped files.
|
|
418
|
-
* @private
|
|
419
|
-
*/
|
|
420
|
-
async handleOnDrop(event) {
|
|
421
|
-
event.preventDefault();
|
|
422
|
-
event.stopImmediatePropagation();
|
|
423
|
-
const requests = await this.uploadService.add(event.dataTransfer?.files);
|
|
424
|
-
this.onChanged.emit({
|
|
425
|
-
component: this,
|
|
426
|
-
requests,
|
|
427
|
-
isUserInteraction: true,
|
|
428
|
-
});
|
|
429
|
-
this.removeZone();
|
|
430
|
-
this.cdr.detectChanges();
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Handles drag over events to allow dropping.
|
|
434
|
-
* @private
|
|
435
|
-
*/
|
|
436
|
-
handleDragOver(event) {
|
|
437
|
-
event.preventDefault();
|
|
438
|
-
event.stopImmediatePropagation();
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Creates the visual overlay for drag and drop feedback.
|
|
442
|
-
* @private
|
|
443
|
-
*/
|
|
444
|
-
async createZone() {
|
|
445
|
-
if (isPlatformBrowser(this.platformID)) {
|
|
446
|
-
this.overlayElement = this.document.createElement('div');
|
|
447
|
-
this.overlayElement.classList.add('ax-uploader-overlay-state', '-ax-z-1');
|
|
448
|
-
this.overlayElement.id = 'ax-uploader-overlay-state';
|
|
449
|
-
const icon = this.document.createElement('span');
|
|
450
|
-
icon.classList.add('ax-icon', 'ax-icon-upload');
|
|
451
|
-
const text = this.document.createElement('span');
|
|
452
|
-
text.innerText = await this.translateService.translateAsync('@acorex:uploader.zone.text');
|
|
453
|
-
this.overlayElement.appendChild(icon);
|
|
454
|
-
this.overlayElement.appendChild(text);
|
|
455
|
-
this.element.appendChild(this.overlayElement);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Removes the visual overlay for drag and drop feedback.
|
|
460
|
-
* @private
|
|
461
|
-
*/
|
|
462
|
-
removeZone() {
|
|
463
|
-
if (isPlatformBrowser(this.platformID)) {
|
|
464
|
-
this.element.removeChild(this.document.getElementById('ax-uploader-overlay-state'));
|
|
465
|
-
this.overlayElement.remove();
|
|
466
|
-
//console.log(this.overlayElement);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Opens the file browser dialog and processes selected files.
|
|
471
|
-
* @returns Promise that resolves when files are processed
|
|
472
|
-
*/
|
|
473
|
-
async browser() {
|
|
474
|
-
const requests = await this.uploadService.browse({ accept: this.accept, multiple: this.multiple });
|
|
475
|
-
this.onChanged.emit({
|
|
476
|
-
component: this,
|
|
477
|
-
requests,
|
|
478
|
-
isUserInteraction: true,
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Host binding for CSS class.
|
|
483
|
-
* @ignore
|
|
484
|
-
*/
|
|
485
|
-
get __hostClass() {
|
|
486
|
-
return `ax-drop-zone`;
|
|
487
|
-
}
|
|
488
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderZoneDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
489
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: AXUploaderZoneDirective, isStandalone: true, selector: "[axUploaderZone]", inputs: { multiple: "multiple", accept: "accept" }, outputs: { onChanged: "onChanged", onFileUploadComplete: "onFileUploadComplete", onFilesUploadComplete: "onFilesUploadComplete" }, host: { properties: { "class": "this.__hostClass" } }, providers: [AXUnsubscriber], ngImport: i0 }); }
|
|
490
|
-
}
|
|
491
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderZoneDirective, decorators: [{
|
|
492
|
-
type: Directive,
|
|
493
|
-
args: [{
|
|
494
|
-
selector: '[axUploaderZone]',
|
|
495
|
-
providers: [AXUnsubscriber],
|
|
496
|
-
}]
|
|
497
|
-
}], ctorParameters: () => [], propDecorators: { multiple: [{
|
|
498
|
-
type: Input
|
|
499
|
-
}], accept: [{
|
|
500
|
-
type: Input
|
|
501
|
-
}], onChanged: [{
|
|
502
|
-
type: Output
|
|
503
|
-
}], onFileUploadComplete: [{
|
|
504
|
-
type: Output
|
|
505
|
-
}], onFilesUploadComplete: [{
|
|
506
|
-
type: Output
|
|
507
|
-
}], __hostClass: [{
|
|
508
|
-
type: HostBinding,
|
|
509
|
-
args: ['class']
|
|
510
|
-
}] } });
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* A directive that provides browse functionality for file uploads.
|
|
514
|
-
* When applied to an element, clicking it will trigger the file browser dialog.
|
|
515
|
-
* @category Directives
|
|
516
|
-
*/
|
|
517
|
-
class AXUploaderBrowseDirective {
|
|
518
|
-
constructor() {
|
|
519
|
-
/**
|
|
520
|
-
* The uploader zone directive instance.
|
|
521
|
-
* @ignore
|
|
522
|
-
*/
|
|
523
|
-
this.uploaderZone = inject(AXUploaderZoneDirective);
|
|
524
|
-
/**
|
|
525
|
-
* The element reference for the directive host.
|
|
526
|
-
* @ignore
|
|
527
|
-
*/
|
|
528
|
-
this.elemenrRef = inject((ElementRef));
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Initializes the directive by adding click event listener and data attribute.
|
|
532
|
-
*/
|
|
533
|
-
ngOnInit() {
|
|
534
|
-
this.elemenrRef.nativeElement.addEventListener('click', this.handleClick.bind(this));
|
|
535
|
-
this.elemenrRef.nativeElement.dataset['axUploaderBrowseHandle'] = 'true';
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Cleans up the directive by removing event listeners.
|
|
539
|
-
*/
|
|
540
|
-
ngOnDestroy() {
|
|
541
|
-
this.elemenrRef.nativeElement.removeEventListener('click', this.handleClick.bind(this));
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Handles the click event to trigger file browser.
|
|
545
|
-
* @private
|
|
546
|
-
*/
|
|
547
|
-
async handleClick() {
|
|
548
|
-
await this.uploaderZone.browser();
|
|
549
|
-
}
|
|
550
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderBrowseDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
551
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: AXUploaderBrowseDirective, isStandalone: true, selector: "[axUploaderBrowseHandle]", ngImport: i0 }); }
|
|
552
|
-
}
|
|
553
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderBrowseDirective, decorators: [{
|
|
554
|
-
type: Directive,
|
|
555
|
-
args: [{ selector: '[axUploaderBrowseHandle]' }]
|
|
556
|
-
}] });
|
|
2
|
+
import { AXTranslatorPipe } from '@acorex/core/translation';
|
|
3
|
+
import { AsyncPipe, NgClass } from '@angular/common';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { inject, ViewEncapsulation, Component, input, NgModule } from '@angular/core';
|
|
6
|
+
import { AXUploaderService } from '@acorex/cdk/uploader';
|
|
7
|
+
import { AXProgressBarComponent } from '@acorex/components/progress-bar';
|
|
8
|
+
import { AXFormatPipe } from '@acorex/core/format';
|
|
9
|
+
import { AXDecoratorIconComponent } from '@acorex/components/decorators';
|
|
557
10
|
|
|
558
11
|
/**
|
|
559
12
|
* A component that displays a list of uploaded files.
|
|
@@ -575,11 +28,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
|
|
|
575
28
|
args: [{ selector: 'ax-uploader-list', encapsulation: ViewEncapsulation.None, imports: [AXProgressBarComponent, AsyncPipe, AXTranslatorPipe, AXFormatPipe], providers: [{ provide: AXComponent, useExisting: AXUploaderListComponent }], template: "<!-- @if ((uploadService.totalEstimateTime | async) > 0) { -->\n<div class=\"ax-uploader-progress-status\" [class.ax-hide]=\"(uploadService.totalEstimateTime | async) <= 0\">\n @if (uploadService.isAnyDetermined()) {\n <span>{{ '@acorex:common.status.processing' | translate | async }}</span>\n } @else {\n <div>{{ uploadService.totalEstimateTime | async | format: 'timeleft' | async }}</div>\n }\n <button (click)=\"uploadService.cancelAll()\">{{ '@acorex:common.actions.cancel' | translate | async }}</button>\n</div>\n<!-- } -->\n\n<ul class=\"ax-uploader-list-items\">\n @for (item of uploadService.files | async; track item.name) {\n <li>\n <div class=\"ax-file\">\n <span>{{ item.ext }}</span>\n </div>\n <div class=\"ax-item-container\">\n <div class=\"ax-item-name\" [title]=\"item.name\">{{ item.name }}</div>\n <div class=\"ax-status\">\n @switch (item.status()) {\n @case ('inprogress') {\n <span>{{ item.size | format: 'filesize' | async }}</span> /\n {{\n item.isDetermined()\n ? (item.estimateTime() | format: 'timeleft' | async)\n : ('@acorex:common.status.processing' | translate | async)\n }}\n }\n @case ('failed') {\n <div class=\"ax-state-failed\">\n <span>{{ item.message() }}</span>\n </div>\n }\n @case ('completed') {\n <div class=\"ax-state-completed\">\n <span>{{ '@acorex:common.status.completed' | translate | async }}</span>\n </div>\n }\n }\n </div>\n </div>\n <div class=\"ax-status\">\n @switch (item.status()) {\n @case ('completed') {\n <i class=\"ax-icon ax-icon-solid ax-icon-check-circle ax-state-completed\"></i>\n }\n @case ('canceled') {\n <div>\n <span class=\"ax-state-canceled\">{{ '@acorex:common.actions.canceled' | translate | async }}</span>\n <!-- <i class=\"ax-icon ax-icon-solid ax-icon-redo\" (click)=\"item.redo()\" title=\"{{ 'retry' | translate | async }}\"></i> -->\n </div>\n }\n @case ('failed') {\n <div class=\"ax-state-failed\">\n <span>{{ '@acorex:common.status.failed' | translate | async }}</span>\n <i\n class=\"ax-icon ax-icon-solid ax-icon-redo\"\n (click)=\"item.redo()\"\n title=\"{{ '@acorex:common.actions.retry' | translate | async }}\"\n ></i>\n </div>\n }\n @default {\n <!-- <ax-circular-progress\n [mode]=\"item.isDetermined() ? 'determinate' : 'indeterminate'\"\n [size]=\"22\"\n [stroke]=\"6\"\n [progress]=\"item.isDetermined() ? item.progress() : 60\"\n class=\"ax-show\"\n >\n </ax-circular-progress> -->\n <i\n class=\"ax-icon ax-icon-solid ax-icon-close\"\n (click)=\"item.cancel()\"\n title=\"{{ '@acorex:common.actions.cancel' | translate | async }}\"\n ></i>\n }\n }\n </div>\n </li>\n @let completed = item.status() === 'completed';\n @if (item.status() === 'inprogress' || completed) {\n <div class=\"ax-status-loading\" [class.ax-status-loading-hide]=\"completed\">\n <ax-progress-bar\n [height]=\"4\"\n [mode]=\"completed ? 'determinate' : 'indeterminate'\"\n [progress]=\"completed ? 100 : 60\"\n [color]=\"completed ? 'success' : 'primary'\"\n ></ax-progress-bar>\n </div>\n }\n }\n</ul>\n", styles: ["ax-uploader-list .ax-uploader-progress-status{display:flex;align-items:center;justify-content:space-between;border-bottom-width:1px;border-top-width:1px;border-color:rgba(var(--ax-sys-color-primary-lightest-surface));background-color:rgba(var(--ax-sys-color-primary-lightest-surface));padding:.5rem .75rem;font-size:.875rem;line-height:1.25rem;color:rgba(var(--ax-sys-color-on-primary-lightest-surface));transition:.3s ease-out}ax-uploader-list .ax-uploader-progress-status.ax-hide{opacity:0;overflow:hidden;height:0;padding-top:0;padding-bottom:0;transition:.3s ease-out}ax-uploader-list .ax-uploader-list-items{max-height:75vh;width:100%;overflow-y:auto;overflow-x:hidden;gap:.5rem;display:flex;flex-direction:column}ax-uploader-list .ax-uploader-list-items li{display:flex;padding:.5rem 1rem;align-items:center;font-size:.875rem;line-height:1.25rem;gap:1rem;width:100%}ax-uploader-list .ax-uploader-list-items li .ax-item-container{display:flex;flex-direction:column;flex:1;-webkit-user-select:none;user-select:none}ax-uploader-list .ax-uploader-list-items li .ax-item-container .ax-item-name{font-size:.875rem;line-height:1.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;width:12rem}ax-uploader-list .ax-uploader-list-items li .ax-status{position:relative;color:rgba(var(--ax-sys-color-on-surface),.5)}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-icon{font-size:1.375rem}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-icon-close{cursor:pointer}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-state-canceled span{color:rgba(var(--ax-sys-color-secondary-surface))}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-state-failed{display:flex;align-items:center;gap:.5rem}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-state-failed span{color:rgba(var(--ax-sys-color-danger-surface))}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-state-failed i{cursor:pointer}ax-uploader-list .ax-uploader-list-items li .ax-status .ax-state-completed{color:rgba(var(--ax-sys-color-success-surface))}ax-uploader-list .ax-uploader-list-items li:hover .ax-hide{display:flex!important}ax-uploader-list .ax-uploader-list-items li:hover .ax-show{display:none!important}ax-uploader-list .ax-uploader-list-items li .ax-show{display:flex!important}ax-uploader-list .ax-uploader-list-items li .ax-hide{display:none!important}ax-uploader-list .ax-uploader-list-items .ax-status-loading.ax-status-loading-hide{transition:all 1s linear;opacity:0;overflow:hidden}.ax-file{position:relative;display:flex;align-items:center;justify-content:center;width:1.5rem;aspect-ratio:.7;border-radius:.25rem;color:rgba(var(--ax-sys-color-light-surface));background-color:rgba(var(--ax-sys-color-success-surface))!important}.ax-file>*{position:absolute;bottom:.3rem;font-weight:700;font-size:.65rem;line-height:.65rem}.ax-file:before{content:\"\";position:absolute;top:0;right:0;border-width:0 12px 12px 0;border-color:rgba(var(--ax-sys-color-surface)) rgba(var(--ax-sys-color-surface)) rgba(var(--ax-sys-color-on-surface),.3) rgba(var(--ax-sys-color-on-surface),.3)}\n"] }]
|
|
576
29
|
}] });
|
|
577
30
|
|
|
578
|
-
var uploaderList_component = /*#__PURE__*/Object.freeze({
|
|
579
|
-
__proto__: null,
|
|
580
|
-
AXUploaderListComponent: AXUploaderListComponent
|
|
581
|
-
});
|
|
582
|
-
|
|
583
31
|
/**
|
|
584
32
|
* A container for managing the uploader dialog with collapse and expand animations.
|
|
585
33
|
* @category Components
|
|
@@ -645,62 +93,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
|
|
|
645
93
|
args: [{ selector: 'ax-uploader-drop-zone', encapsulation: ViewEncapsulation.None, imports: [AXDecoratorIconComponent, AsyncPipe, AXTranslatorPipe], providers: [{ provide: AXComponent, useExisting: AXUploaderDropZoneComponent }], template: "<div class=\"ax-uploader-drop-zone-container\">\n <ax-icon class=\"ax-icon ax-icon-upload\"></ax-icon>\n <div class=\"ax-uploader-drop-zone-description\">\n <span>\n {{ '@acorex:uploader.zone.drag' | translate | async }}\n <a href=\"\" (click)=\"preventRefresh()\">\n {{ '@acorex:uploader.zone.choose' | translate | async }}\n </a>\n {{ '@acorex:uploader.zone.to-upload' | translate | async }}\n </span>\n <!-- <p>SVG, PNG, JPG or GIF (MAX. 800x400px)</p> -->\n @if (description()) {\n <p>{{ description() }}</p>\n }\n </div>\n</div>\n", styles: ["ax-uploader-drop-zone{width:100%;height:100%;display:block;cursor:pointer}ax-uploader-drop-zone .ax-uploader-drop-zone-container{display:flex;flex-direction:column;align-items:center;justify-content:center;border-radius:.5rem;margin:1rem;padding:1rem;gap:1rem;border:2px dashed;border-color:rgba(var(--ax-sys-color-border-lightest-surface));pointer-events:none}ax-uploader-drop-zone .ax-uploader-drop-zone-container:hover{border-color:rgba(var(--ax-sys-color-primary-surface));background-color:rgba(var(--ax-sys-color-primary-lightest-surface))}ax-uploader-drop-zone .ax-uploader-drop-zone-container ax-icon{font-size:1.875rem;line-height:2.25rem;color:#a3a3a3;width:1.75rem;height:2rem}ax-uploader-drop-zone .ax-uploader-drop-zone-container .ax-uploader-drop-zone-description{display:flex;flex-direction:column;gap:.5rem}ax-uploader-drop-zone .ax-uploader-drop-zone-container .ax-uploader-drop-zone-description a{color:rgba(var(--ax-sys-color-primary-surface))}ax-uploader-drop-zone .ax-uploader-drop-zone-container .ax-uploader-drop-zone-description p{font-size:.875rem;line-height:1.25rem;color:#a3a3a3}\n"] }]
|
|
646
94
|
}], propDecorators: { description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
647
95
|
|
|
648
|
-
const COMPONENTS = [
|
|
649
|
-
AXUploaderDropZoneComponent,
|
|
650
|
-
AXUploaderListComponent,
|
|
651
|
-
AXUploaderZoneDirective,
|
|
652
|
-
AXUploaderBrowseDirective,
|
|
653
|
-
AXUploaderDialogContainerComponent,
|
|
654
|
-
];
|
|
96
|
+
const COMPONENTS = [AXUploaderListComponent, AXUploaderDialogContainerComponent];
|
|
655
97
|
class AXUploaderModule {
|
|
656
98
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
657
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, imports: [
|
|
658
|
-
|
|
659
|
-
AXButtonModule,
|
|
660
|
-
AXTranslationModule,
|
|
661
|
-
AXProgressBarModule,
|
|
662
|
-
AXFormatModule,
|
|
663
|
-
AXFileModule,
|
|
664
|
-
AXDateTimeModule,
|
|
665
|
-
AXCircularProgressModule,
|
|
666
|
-
AXPopupModule, AXUploaderDropZoneComponent,
|
|
667
|
-
AXUploaderListComponent,
|
|
668
|
-
AXUploaderZoneDirective,
|
|
669
|
-
AXUploaderBrowseDirective,
|
|
670
|
-
AXUploaderDialogContainerComponent], exports: [AXUploaderDropZoneComponent,
|
|
671
|
-
AXUploaderListComponent,
|
|
672
|
-
AXUploaderZoneDirective,
|
|
673
|
-
AXUploaderBrowseDirective,
|
|
674
|
-
AXUploaderDialogContainerComponent] }); }
|
|
675
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, imports: [CommonModule,
|
|
676
|
-
AXDecoratorModule,
|
|
677
|
-
AXButtonModule,
|
|
678
|
-
AXTranslationModule,
|
|
679
|
-
AXProgressBarModule,
|
|
680
|
-
AXFormatModule,
|
|
681
|
-
AXFileModule,
|
|
682
|
-
AXDateTimeModule,
|
|
683
|
-
AXCircularProgressModule,
|
|
684
|
-
AXPopupModule, AXUploaderDropZoneComponent,
|
|
685
|
-
AXUploaderListComponent,
|
|
686
|
-
AXUploaderDialogContainerComponent] }); }
|
|
99
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, imports: [AXUploaderListComponent, AXUploaderDialogContainerComponent], exports: [AXUploaderListComponent, AXUploaderDialogContainerComponent] }); }
|
|
100
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, imports: [COMPONENTS] }); }
|
|
687
101
|
}
|
|
688
102
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AXUploaderModule, decorators: [{
|
|
689
103
|
type: NgModule,
|
|
690
104
|
args: [{
|
|
691
|
-
imports: [
|
|
692
|
-
CommonModule,
|
|
693
|
-
AXDecoratorModule,
|
|
694
|
-
AXButtonModule,
|
|
695
|
-
AXTranslationModule,
|
|
696
|
-
AXProgressBarModule,
|
|
697
|
-
AXFormatModule,
|
|
698
|
-
AXFileModule,
|
|
699
|
-
AXDateTimeModule,
|
|
700
|
-
AXCircularProgressModule,
|
|
701
|
-
AXPopupModule,
|
|
702
|
-
...COMPONENTS,
|
|
703
|
-
],
|
|
105
|
+
imports: [...COMPONENTS],
|
|
704
106
|
exports: [...COMPONENTS],
|
|
705
107
|
providers: [],
|
|
706
108
|
}]
|
|
@@ -710,5 +112,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
|
|
|
710
112
|
* Generated bundle index. Do not edit.
|
|
711
113
|
*/
|
|
712
114
|
|
|
713
|
-
export {
|
|
115
|
+
export { AXUploaderDialogContainerComponent, AXUploaderDropZoneComponent, AXUploaderListComponent, AXUploaderModule };
|
|
714
116
|
//# sourceMappingURL=acorex-components-uploader.mjs.map
|