001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.addins.client.fileuploader;
021
022import com.google.gwt.core.client.GWT;
023import com.google.gwt.dom.client.Document;
024import com.google.gwt.dom.client.Element;
025import com.google.gwt.event.shared.HandlerRegistration;
026import com.google.gwt.user.client.DOM;
027import gwt.material.design.addins.client.MaterialAddins;
028import gwt.material.design.addins.client.base.constants.AddinsCssName;
029import gwt.material.design.addins.client.fileuploader.base.HasFileUpload;
030import gwt.material.design.addins.client.fileuploader.base.UploadFile;
031import gwt.material.design.addins.client.fileuploader.base.UploadResponse;
032import gwt.material.design.addins.client.fileuploader.constants.FileMethod;
033import gwt.material.design.addins.client.fileuploader.constants.FileUploaderEvents;
034import gwt.material.design.addins.client.fileuploader.events.*;
035import gwt.material.design.addins.client.fileuploader.js.Dropzone;
036import gwt.material.design.addins.client.fileuploader.js.File;
037import gwt.material.design.addins.client.fileuploader.js.JsFileUploaderOptions;
038import gwt.material.design.client.MaterialDesignBase;
039import gwt.material.design.client.base.JsLoader;
040import gwt.material.design.client.base.MaterialWidget;
041import gwt.material.design.client.constants.CssName;
042import gwt.material.design.client.constants.Display;
043import gwt.material.design.client.events.*;
044import gwt.material.design.client.ui.MaterialToast;
045import gwt.material.design.jquery.client.api.JQueryElement;
046
047import java.util.Date;
048
049import static gwt.material.design.jquery.client.api.JQuery.$;
050
051//@formatter:off
052
053/**
054 * Custom file uploader with Dnd support with the help of dropzone.js. It has multiple
055 * feature just like the GWT File Uploader core widget.
056 * <p>
057 * <h3>XML Namespace Declaration</h3>
058 * <pre>
059 * {@code
060 * xmlns:ma='urn:import:gwt.material.design.addins.client'
061 * }
062 * </pre>
063 * <p>
064 * <h3>UiBinder Usage:</h3>
065 * <pre>
066 * {@code
067 * <ma:fileuploader.MaterialFileUploader url="/file/upload"/>
068 * }
069 * </pre>
070 *
071 * @author kevzlou7979
072 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#fileuploader">File Uploader</a>
073 * @see <a href="https://github.com/enyo/dropzone">Dropzone 4.3.0</a>
074 */
075//@formatter:on
076public class MaterialFileUploader extends MaterialWidget implements JsLoader, HasFileUpload<UploadFile> {
077
078    static {
079        if (MaterialAddins.isDebug()) {
080            MaterialDesignBase.injectDebugJs(MaterialFileUploaderDebugClientBundle.INSTANCE.dropzoneJsDebug());
081            MaterialDesignBase.injectCss(MaterialFileUploaderDebugClientBundle.INSTANCE.dropzoneCssDebug());
082        } else {
083            MaterialDesignBase.injectJs(MaterialFileUploaderClientBundle.INSTANCE.dropzoneJs());
084            MaterialDesignBase.injectCss(MaterialFileUploaderClientBundle.INSTANCE.dropzoneCss());
085        }
086    }
087
088    private boolean preview = true;
089    private boolean enabled = true;
090    private int totalFiles = 0;
091    private String globalResponse = "";
092    private Dropzone uploader;
093    private MaterialUploadPreview uploadPreview = new MaterialUploadPreview();
094    private JsFileUploaderOptions options = new JsFileUploaderOptions();
095
096    public MaterialFileUploader() {
097        super(Document.get().createDivElement(), AddinsCssName.FILEUPLOADER);
098
099        setId(AddinsCssName.ZDROP);
100        add(uploadPreview);
101    }
102
103    public MaterialFileUploader(String url, FileMethod method) {
104        this();
105        setUrl(url);
106        setMethod(method);
107    }
108
109    public MaterialFileUploader(String url, FileMethod method, int maxFileSize, String acceptedFiles) {
110        this(url, method);
111        setMaxFiles(maxFileSize);
112        setAcceptedFiles(acceptedFiles);
113    }
114
115    @Override
116    protected void onLoad() {
117        super.onLoad();
118
119        if (getWidgetCount() > 1) {
120            uploadPreview.getUploadCollection().setId(DOM.createUniqueId());
121            if (options.clickable == null) {
122                String clickable = DOM.createUniqueId();
123                options.clickable = "#" + clickable;
124                if (getWidget(1) instanceof MaterialUploadLabel) {
125                    MaterialUploadLabel label = (MaterialUploadLabel) getWidget(1);
126                    label.getIcon().setId(clickable);
127                } else {
128                    getWidget(1).getElement().setId(clickable);
129                }
130
131            }
132
133            if (!isPreview()) {
134                uploadPreview.setDisplay(Display.NONE);
135            }
136
137            load();
138
139        } else {
140            GWT.log("You don't have any child widget to use as a upload label");
141        }
142
143        setEnabled(enabled);
144    }
145
146    @Override
147    public void load() {
148        MaterialUploadCollection uploadCollection = uploadPreview.getUploadCollection();
149        if (uploadCollection != null) {
150            initDropzone(getElement(),
151                    uploadCollection.getItem().getElement(),
152                    uploadCollection.getId(),
153                    uploadCollection.getElement(),
154                    uploadPreview.getUploadHeader().getUploadedFiles().getElement());
155        }
156    }
157
158    @Override
159    protected void onUnload() {
160        super.onUnload();
161        unload();
162    }
163
164    @Override
165    public void unload() {
166        if (uploader != null) {
167            uploader.destroy();
168        }
169    }
170
171    @Override
172    public void reload() {
173        unload();
174        load();
175    }
176
177
178    /**
179     * Intialize the dropzone component with element and form url to provide a
180     * dnd feature for the file upload
181     *
182     * @param e
183     */
184    protected void initDropzone(Element e, Element template, String previews, Element uploadPreview, Element uploadedFiles) {
185        JQueryElement previewNode = $(template);
186        previewNode.asElement().setId("");
187        String previewTemplate = previewNode.parent().html();
188        options.previewTemplate = previewTemplate;
189        options.previewsContainer = "#" + previews;
190        uploader = new Dropzone(e, options);
191
192        uploader.on(FileUploaderEvents.DROP, event -> {
193            fireDropEvent();
194            if (preview) {
195                $(e).removeClass(CssName.ACTIVE);
196            }
197            return true;
198        });
199
200        uploader.on(FileUploaderEvents.DRAG_START, event -> {
201            DragStartEvent.fire(this);
202            return true;
203        });
204
205        uploader.on(FileUploaderEvents.DRAG_END, event -> {
206            DragEndEvent.fire(this);
207            return true;
208        });
209
210        uploader.on(FileUploaderEvents.DRAG_ENTER, event -> {
211            DragEnterEvent.fire(this, null);
212            if (preview) {
213                $(e).addClass(CssName.ACTIVE);
214            }
215            return true;
216        });
217
218        uploader.on(FileUploaderEvents.DRAG_OVER, event -> {
219            DragOverEvent.fire(this);
220            return true;
221        });
222
223        uploader.on(FileUploaderEvents.DRAG_LEAVE, event -> {
224            DragLeaveEvent.fire(this, null);
225            if (preview) {
226                $(e).removeClass(CssName.ACTIVE);
227            }
228            return true;
229        });
230
231        uploader.on(FileUploaderEvents.ADDED_FILE, file -> {
232            AddedFileEvent.fire(this, convertUploadFile(file));
233            totalFiles++;
234
235            if (isPreview()) {
236                $(uploadPreview).css("visibility", "visible");
237                $(uploadedFiles).html("Uploaded files " + totalFiles);
238                getUploadPreview().getUploadHeader().getProgress().setPercent(0);
239            }
240        });
241
242        uploader.on(FileUploaderEvents.REMOVED_FILE, file -> {
243            RemovedFileEvent.fire(this, convertUploadFile(file));
244            totalFiles -= 1;
245            $(uploadedFiles).html("Uploaded files " + totalFiles);
246        });
247
248        uploader.on("error", (file, response) -> {
249            String code = "200";
250            if (file.xhr != null) {
251                code = file.xhr.status;
252            }
253
254            if (response.indexOf("401") >= 0) {
255                response = "Unauthorized. Your session may have expired. Log in and try again.";
256                globalResponse = response;
257                UnauthorizedEvent.fire(this, convertUploadFile(file), new UploadResponse(file.xhr.status, file.xhr.statusText, response));
258            }
259
260            if (response.indexOf("404") >= 0) {
261                response = "There is a problem uploading your file.";
262                globalResponse = response;
263            }
264
265            if (response.indexOf("500") >= 0) {
266                response = "There is a problem uploading your file.";
267                globalResponse = response;
268            }
269
270            $(file.previewElement).find("#error-message").html(response);
271            ErrorEvent.fire(this, convertUploadFile(file), new UploadResponse(file.xhr.status, file.xhr.statusText, response));
272        });
273
274        uploader.on(FileUploaderEvents.TOTAL_UPLOAD_PROGRESS, (progress, file, response) -> {
275            TotalUploadProgressEvent.fire(this, progress);
276            if (isPreview()) {
277                getUploadPreview().getUploadHeader().getProgress().setPercent(progress);
278            }
279        });
280
281        uploader.on(FileUploaderEvents.UPLOAD_PROGRESS, (progress, file, response) -> {
282            CurrentUploadProgressEvent.fire(this, progress);
283            if ($this != null) {
284                $this.find(".progress .determinate").css("width", progress + "%");
285            }
286        });
287
288        uploader.on(FileUploaderEvents.SENDING, file -> {
289            SendingEvent.fire(this, convertUploadFile(file), new UploadResponse(file.xhr.status, file.xhr.statusText));
290        });
291
292        uploader.on(FileUploaderEvents.SUCCESS, (file, response) -> {
293            globalResponse = response;
294            SuccessEvent.fire(this, convertUploadFile(file), new UploadResponse(file.xhr.status, file.xhr.statusText, response));
295        });
296
297        uploader.on(FileUploaderEvents.COMPLETE, file -> {
298            CompleteEvent.fire(this, convertUploadFile(file), new UploadResponse(file.xhr.status, file.xhr.statusText, globalResponse));
299        });
300
301        uploader.on(FileUploaderEvents.CANCELED, file -> {
302            CanceledEvent.fire(this, convertUploadFile(file));
303        });
304
305        uploader.on(FileUploaderEvents.MAX_FILES_REACHED, file -> {
306            MaxFilesReachedEvent.fire(this, convertUploadFile(file));
307        });
308
309        uploader.on(FileUploaderEvents.MAX_FILES_EXCEEDED, file -> {
310            MaterialToast.fireToast("You have reached the maximum files to be uploaded.");
311            MaxFilesExceededEvent.fire(this, convertUploadFile(file));
312        });
313    }
314
315
316    @Override
317    public void setEnabled(boolean enabled) {
318        this.enabled = enabled;
319
320        if (enabled) {
321            if (uploader != null) uploader.setupEventListeners();
322            removeStyleName(CssName.DISABLED);
323        } else {
324            if (uploader != null) uploader.removeEventListeners();
325            addStyleName(CssName.DISABLED);
326        }
327
328        getEnabledMixin().updateWaves(enabled, this);
329    }
330
331    @Override
332    public boolean isEnabled() {
333        return !getElement().hasClassName(CssName.DISABLED);
334    }
335
336    /**
337     * Converts a Native File Object to Upload File object
338     */
339    protected UploadFile convertUploadFile(File file) {
340        Date lastModifiedDate = new Date();
341        // Avoid parsing error on last modified date
342        if (file.lastModifiedDate != null && !file.lastModifiedDate.isEmpty()) {
343            lastModifiedDate = new Date(file.lastModifiedDate);
344        }
345        return new UploadFile(file.name, lastModifiedDate, Double.parseDouble(file.size), file.type);
346    }
347
348    /**
349     * Manually start upload queued files when option autoProcessQueue is disabled
350     */
351    public void processQueue() {
352        uploader.processQueue();
353    }
354
355    /**
356     * Manually enqueue file when option autoQueue is disabled
357     */
358    public void enqueueFile(File file) {
359        uploader.enqueueFile(file);
360    }
361
362    /**
363     * Get the form url.
364     */
365    public String getUrl() {
366        return options.url;
367    }
368
369    /**
370     * Set the form url e.g /file/post.
371     */
372    public void setUrl(String url) {
373        options.url = url;
374    }
375
376    /**
377     * Get the maximum file size value of the uploader.
378     */
379    public int getMaxFileSize() {
380        return options.maxFilesize;
381    }
382
383    /**
384     * Set the maximum file size of the uploader, default 20(MB).
385     */
386    public void setMaxFileSize(int maxFileSize) {
387        options.maxFilesize = maxFileSize;
388    }
389
390    /**
391     * Check whether it's auto process queue or not.
392     */
393    public boolean isAutoProcessQueue() {
394        return options.autoProcessQueue;
395    }
396
397    /**
398     * Set the auto process queue boolean value.
399     */
400    public void setAutoProcessQueue(boolean autoProcessQueue) {
401        options.autoProcessQueue = autoProcessQueue;
402    }
403
404    /**
405     * Check whether it's auto queue or not.
406     */
407    public boolean isAutoQueue() {
408        return options.autoQueue;
409    }
410
411    /**
412     * Set the auto queue boolean value.
413     */
414    public void setAutoQueue(boolean autoQueue) {
415        options.autoQueue = autoQueue;
416    }
417
418    /**
419     * Get the method param of file uploader.
420     */
421    public FileMethod getMethod() {
422        return FileMethod.fromStyleName(options.method);
423    }
424
425    /**
426     * Set the method param of file upload (POST or PUT), default POST.
427     */
428    public void setMethod(FileMethod method) {
429        options.method = method.getCssName();
430    }
431
432    /**
433     * Get the max number of files.
434     */
435    public int getMaxFiles() {
436        return options.maxFiles;
437    }
438
439    /**
440     * Set the max number of files.
441     * Default 100 but if you want to accept only one file just set the max file to 1.
442     * If the number of files you upload exceeds, the event maxfilesexceeded will be called.
443     */
444    public void setMaxFiles(int maxFiles) {
445        options.maxFiles = maxFiles;
446    }
447
448    /**
449     * Check whether it's withCredentials or not.
450     */
451    public boolean isWithCredentials() {
452        return options.withCredentials;
453    }
454
455    /**
456     * Set the withCredentials boolean value.
457     */
458    public void setWithCredentials(boolean withCredentials) {
459        options.withCredentials = withCredentials;
460    }
461
462    /**
463     * Get the accepted file string.
464     */
465    public String getAcceptedFiles() {
466        return options.acceptedFiles;
467    }
468
469    /**
470     * Set the default implementation of accept checks the file's mime type or extension against this list.
471     * This is a comma separated list of mime types or file extensions. Eg.: image/*,application/pdf,.psd.
472     */
473    public void setAcceptedFiles(String acceptedFiles) {
474        options.acceptedFiles = acceptedFiles;
475    }
476
477    public void fireDropEvent() {
478        DropEvent.fire(this, null);
479    }
480
481    public String getClickable() {
482        return options.clickable.length() == 0 ? options.clickable : options.clickable.substring(1);
483    }
484
485    public void setClickable(String clickable) {
486        options.clickable = "#" + clickable;
487    }
488
489    public boolean isPreview() {
490        return preview;
491    }
492
493    public void setPreview(boolean preview) {
494        this.preview = preview;
495    }
496
497    public void reset() {
498        uploader.removeAllFiles();
499    }
500
501    public MaterialUploadPreview getUploadPreview() {
502        return uploadPreview;
503    }
504
505    public String getDictDefaultMessage() {
506        return options.dictDefaultMessage;
507    }
508
509    /**
510     * Defaults to "Drop files here to upload"
511     */
512    public void setDictDefaultMessage(String dictDefaultMessage) {
513        options.dictDefaultMessage = dictDefaultMessage;
514    }
515
516    public String getDictFallbackMessage() {
517        return options.dictFallbackMessage;
518    }
519
520    /**
521     * Defaults to "Your browser does not support drag'n'drop file uploads."\
522     */
523    public void setDictFallbackMessage(String dictFallbackMessage) {
524        options.dictFallbackMessage = dictFallbackMessage;
525    }
526
527    public String getDictFallbackText() {
528        return options.dictFallbackText;
529    }
530
531    /**
532     * Defaults to "Please use the fallback form below to upload your files like in the olden days."
533     */
534    public void setDictFallbackText(String dictFallbackText) {
535        options.dictFallbackText = dictFallbackText;
536    }
537
538    public String getDictFileTooBig() {
539        return options.dictFileTooBig;
540    }
541
542    /**
543     * Defaults to "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB."
544     */
545    public void setDictFileTooBig(String dictFileTooBig) {
546        options.dictFileTooBig = dictFileTooBig;
547    }
548
549    public String getDictInvalidFileType() {
550        return options.dictInvalidFileType;
551    }
552
553    /**
554     * Defaults to "You can't upload files of this type."
555     */
556    public void setDictInvalidFileType(String dictInvalidFileType) {
557        options.dictInvalidFileType = dictInvalidFileType;
558    }
559
560    public String getDictResponseError() {
561        return options.dictResponseError;
562    }
563
564    /**
565     * Defaults to "Server responded with {{statusCode}} code."
566     */
567    public void setDictResponseError(String dictResponseError) {
568        options.dictResponseError = dictResponseError;
569    }
570
571    public String getDictCancelUpload() {
572        return options.dictCancelUpload;
573    }
574
575    /**
576     * Defaults to "Cancel upload"
577     */
578    public void setDictCancelUpload(String dictCancelUpload) {
579        options.dictCancelUpload = dictCancelUpload;
580    }
581
582    public String getDictCancelUploadConfirmation() {
583        return options.dictCancelUploadConfirmation;
584    }
585
586    /**
587     * Defaults to "Are you sure you want to cancel this upload?"
588     */
589    public void setDictCancelUploadConfirmation(String dictCancelUploadConfirmation) {
590        options.dictCancelUploadConfirmation = dictCancelUploadConfirmation;
591    }
592
593    public String getDictRemoveFile() {
594        return options.dictRemoveFile;
595    }
596
597    /**
598     * Defaults to "Remove file"
599     */
600    public void setDictRemoveFile(String dictRemoveFile) {
601        options.dictRemoveFile = dictRemoveFile;
602    }
603
604    public String getDictMaxFilesExceeded() {
605        return options.dictMaxFilesExceeded;
606    }
607
608    /**
609     * Defaults to "You can not upload any more files."
610     */
611    public void setDictMaxFilesExceeded(String dictMaxFilesExceeded) {
612        options.dictMaxFilesExceeded = dictMaxFilesExceeded;
613    }
614
615    @Override
616    public HandlerRegistration addAddedFileHandler(final AddedFileEvent.AddedFileHandler<UploadFile> handler) {
617        return addHandler(new AddedFileEvent.AddedFileHandler<UploadFile>() {
618            @Override
619            public void onAddedFile(AddedFileEvent<UploadFile> event) {
620                if (isEnabled()) {
621                    handler.onAddedFile(event);
622                }
623            }
624        }, AddedFileEvent.getType());
625    }
626
627    @Override
628    public HandlerRegistration addRemovedFileHandler(final RemovedFileEvent.RemovedFileHandler<UploadFile> handler) {
629        return addHandler(new RemovedFileEvent.RemovedFileHandler<UploadFile>() {
630            @Override
631            public void onRemovedFile(RemovedFileEvent<UploadFile> event) {
632                if (isEnabled()) {
633                    handler.onRemovedFile(event);
634                }
635            }
636        }, RemovedFileEvent.getType());
637    }
638
639    @Override
640    public HandlerRegistration addErrorHandler(final ErrorEvent.ErrorHandler<UploadFile> handler) {
641        return addHandler(new ErrorEvent.ErrorHandler<UploadFile>() {
642            @Override
643            public void onError(ErrorEvent<UploadFile> event) {
644                if (isEnabled()) {
645                    handler.onError(event);
646                }
647            }
648        }, ErrorEvent.getType());
649    }
650
651    @Override
652    public HandlerRegistration addUnauthorizedHandler(final UnauthorizedEvent.UnauthorizedHandler<UploadFile> handler) {
653        return addHandler(new UnauthorizedEvent.UnauthorizedHandler<UploadFile>() {
654            @Override
655            public void onUnauthorized(UnauthorizedEvent<UploadFile> event) {
656                if (isEnabled()) {
657                    handler.onUnauthorized(event);
658                }
659            }
660        }, UnauthorizedEvent.getType());
661    }
662
663    @Override
664    public HandlerRegistration addTotalUploadProgressHandler(final TotalUploadProgressEvent.TotalUploadProgressHandler handler) {
665        return addHandler(event -> {
666            if (isEnabled()) {
667                handler.onTotalUploadProgress(event);
668            }
669        }, TotalUploadProgressEvent.TYPE);
670    }
671
672    @Override
673    public HandlerRegistration addCurrentUploadProgressHandler(CurrentUploadProgressEvent.CurrentUploadProgressHandler handler) {
674        return addHandler(event -> {
675            if (isEnabled()) {
676                handler.onCurrentUploadProgress(event);
677            }
678        }, CurrentUploadProgressEvent.TYPE);
679    }
680
681    @Override
682    public HandlerRegistration addSendingHandler(final SendingEvent.SendingHandler<UploadFile> handler) {
683        return addHandler(new SendingEvent.SendingHandler<UploadFile>() {
684            @Override
685            public void onSending(SendingEvent<UploadFile> event) {
686                if (isEnabled()) {
687                    handler.onSending(event);
688                }
689            }
690        }, SendingEvent.getType());
691    }
692
693    @Override
694    public HandlerRegistration addSuccessHandler(final SuccessEvent.SuccessHandler<UploadFile> handler) {
695        return addHandler(new SuccessEvent.SuccessHandler<UploadFile>() {
696            @Override
697            public void onSuccess(SuccessEvent<UploadFile> event) {
698                if (isEnabled()) {
699                    handler.onSuccess(event);
700                }
701            }
702        }, SuccessEvent.getType());
703    }
704
705    @Override
706    public HandlerRegistration addCompleteHandler(final CompleteEvent.CompleteHandler<UploadFile> handler) {
707        return addHandler(new CompleteEvent.CompleteHandler<UploadFile>() {
708            @Override
709            public void onComplete(CompleteEvent<UploadFile> event) {
710                if (isEnabled()) {
711                    handler.onComplete(event);
712                }
713            }
714        }, CompleteEvent.getType());
715    }
716
717    @Override
718    public HandlerRegistration addCancelHandler(final CanceledEvent.CanceledHandler<UploadFile> handler) {
719        return addHandler(new CanceledEvent.CanceledHandler<UploadFile>() {
720            @Override
721            public void onCanceled(CanceledEvent<UploadFile> event) {
722                if (isEnabled()) {
723                    handler.onCanceled(event);
724                }
725            }
726        }, CanceledEvent.getType());
727    }
728
729    @Override
730    public HandlerRegistration addMaxFilesReachHandler(final MaxFilesReachedEvent.MaxFilesReachedHandler<UploadFile> handler) {
731        return addHandler(new MaxFilesReachedEvent.MaxFilesReachedHandler<UploadFile>() {
732            @Override
733            public void onMaxFilesReached(MaxFilesReachedEvent<UploadFile> event) {
734                if (isEnabled()) {
735                    handler.onMaxFilesReached(event);
736                }
737            }
738        }, MaxFilesReachedEvent.getType());
739    }
740
741    @Override
742    public HandlerRegistration addMaxFilesExceededHandler(final MaxFilesExceededEvent.MaxFilesExceededHandler<UploadFile> handler) {
743        return addHandler(new MaxFilesExceededEvent.MaxFilesExceededHandler<UploadFile>() {
744            @Override
745            public void onMaxFilesExceeded(MaxFilesExceededEvent<UploadFile> event) {
746                if (isEnabled()) {
747                    handler.onMaxFilesExceeded(event);
748                }
749            }
750        }, MaxFilesExceededEvent.getType());
751    }
752}