UNPKG

primeng

Version:

PrimeNG is an open source UI library for Angular featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeB

1,206 lines (1,188 loc) 65.4 kB
import * as i1 from '@angular/common'; import { isPlatformBrowser, CommonModule } from '@angular/common'; import { HttpClient, HttpEventType } from '@angular/common/http'; import * as i0 from '@angular/core'; import { Injectable, EventEmitter, inject, NgZone, numberAttribute, booleanAttribute, ContentChildren, Input, ViewChild, ContentChild, Output, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; import { addClass, removeClass } from '@primeuix/utils'; import { TranslationKeys, SharedModule, PrimeTemplate } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { Button } from 'primeng/button'; import { PlusIcon, UploadIcon, TimesIcon } from 'primeng/icons'; import { Message } from 'primeng/message'; import { ProgressBar } from 'primeng/progressbar'; import { BaseStyle } from 'primeng/base'; const theme = ({ dt }) => ` .p-fileupload input[type="file"] { display: none; } .p-fileupload-advanced { border: 1px solid ${dt('fileupload.border.color')}; border-radius: ${dt('fileupload.border.radius')}; background: ${dt('fileupload.background')}; color: ${dt('fileupload.color')}; } .p-fileupload-header { display: flex; align-items: center; padding: ${dt('fileupload.header.padding')}; background: ${dt('fileupload.header.background')}; color: ${dt('fileupload.header.color')}; border-style: solid; border-width: ${dt('fileupload.header.border.width')}; border-color: ${dt('fileupload.header.border.color')}; border-radius: ${dt('fileupload.header.border.radius')}; gap: ${dt('fileupload.header.gap')}; } .p-fileupload-content { border: 1px solid transparent; display: flex; flex-direction: column; gap: ${dt('fileupload.content.gap')}; transition: border-color ${dt('fileupload.transition.duration')}; padding: ${dt('fileupload.content.padding')}; } .p-fileupload-content .p-progressbar { width: 100%; height: ${dt('fileupload.progressbar.height')}; } .p-fileupload-file-list { display: flex; flex-direction: column; gap: ${dt('fileupload.filelist.gap')}; } .p-fileupload-file { display: flex; flex-wrap: wrap; align-items: center; padding: ${dt('fileupload.file.padding')}; border-bottom: 1px solid ${dt('fileupload.file.border.color')}; gap: ${dt('fileupload.file.gap')}; } .p-fileupload-file:last-child { border-bottom: 0; } .p-fileupload-file-info { display: flex; flex-direction: column; gap: ${dt('fileupload.file.info.gap')}; } .p-fileupload-file-thumbnail { flex-shrink: 0; } .p-fileupload-file-actions { margin-left: auto; } .p-fileupload-highlight { border: 1px dashed ${dt('fileupload.content.highlight.border.color')}; } .p-fileupload-advanced .p-message { margin-top: 0; } .p-fileupload-basic { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: ${dt('fileupload.basic.gap')}; } `; const classes = { root: ({ instance }) => `p-fileupload p-fileupload-${instance.mode} p-component`, header: 'p-fileupload-header', pcChooseButton: 'p-fileupload-choose-button', pcUploadButton: 'p-fileupload-upload-button', pcCancelButton: 'p-fileupload-cancel-button', content: 'p-fileupload-content', fileList: 'p-fileupload-file-list', file: 'p-fileupload-file', fileThumbnail: 'p-fileupload-file-thumbnail', fileInfo: 'p-fileupload-file-info', fileName: 'p-fileupload-file-name', fileSize: 'p-fileupload-file-size', pcFileBadge: 'p-fileupload-file-badge', fileActions: 'p-fileupload-file-actions', pcFileRemoveButton: 'p-fileupload-file-remove-button' }; class FileUploadStyle extends BaseStyle { name = 'fileupload'; theme = theme; classes = classes; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: FileUploadStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: FileUploadStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: FileUploadStyle, decorators: [{ type: Injectable }] }); /** * * FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations. * * [Live Demo](https://www.primeng.org/fileupload/) * * @module fileuploadstyle * */ var FileUploadClasses; (function (FileUploadClasses) { /** * Class name of the root element */ FileUploadClasses["root"] = "p-fileupload"; /** * Class name of the header element */ FileUploadClasses["header"] = "p-fileupload-header"; /** * Class name of the choose button element */ FileUploadClasses["pcChooseButton"] = "p-fileupload-choose-button"; /** * Class name of the upload button element */ FileUploadClasses["pcUploadButton"] = "p-fileupload-upload-button"; /** * Class name of the cancel button element */ FileUploadClasses["pcCancelButton"] = "p-fileupload-cancel-button"; /** * Class name of the content element */ FileUploadClasses["content"] = "p-fileupload-content"; /** * Class name of the file list element */ FileUploadClasses["fileList"] = "p-fileupload-file-list"; /** * Class name of the file element */ FileUploadClasses["file"] = "p-fileupload-file"; /** * Class name of the file thumbnail element */ FileUploadClasses["fileThumbnail"] = "p-fileupload-file-thumbnail"; /** * Class name of the file info element */ FileUploadClasses["fileInfo"] = "p-fileupload-file-info"; /** * Class name of the file name element */ FileUploadClasses["fileName"] = "p-fileupload-file-name"; /** * Class name of the file size element */ FileUploadClasses["fileSize"] = "p-fileupload-file-size"; /** * Class name of the file badge element */ FileUploadClasses["pcFileBadge"] = "p-fileupload-file-badge"; /** * Class name of the file actions element */ FileUploadClasses["fileActions"] = "p-fileupload-file-actions"; /** * Class name of the file remove button element */ FileUploadClasses["pcFileRemoveButton"] = "p-fileupload-file-remove-button"; })(FileUploadClasses || (FileUploadClasses = {})); /** * FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations. * @group Components */ class FileUpload extends BaseComponent { /** * Name of the request parameter to identify the files at backend. * @group Props */ name; /** * Remote url to upload the files. * @group Props */ url; /** * HTTP method to send the files to the url such as "post" and "put". * @group Props */ method = 'post'; /** * Used to select multiple files at once from file dialog. * @group Props */ multiple; /** * Comma-separated list of pattern to restrict the allowed file types. Can be any combination of either the MIME types (such as "image/*") or the file extensions (such as ".jpg"). * @group Props */ accept; /** * Disables the upload functionality. * @group Props */ disabled; /** * When enabled, upload begins automatically after selection is completed. * @group Props */ auto; /** * Cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. * @group Props */ withCredentials; /** * Maximum file size allowed in bytes. * @group Props */ maxFileSize; /** * Summary message of the invalid file size. * @group Props */ invalidFileSizeMessageSummary = '{0}: Invalid file size, '; /** * Detail message of the invalid file size. * @group Props */ invalidFileSizeMessageDetail = 'maximum upload size is {0}.'; /** * Summary message of the invalid file type. * @group Props */ invalidFileTypeMessageSummary = '{0}: Invalid file type, '; /** * Detail message of the invalid file type. * @group Props */ invalidFileTypeMessageDetail = 'allowed file types: {0}.'; /** * Detail message of the invalid file type. * @group Props */ invalidFileLimitMessageDetail = 'limit is {0} at most.'; /** * Summary message of the invalid file type. * @group Props */ invalidFileLimitMessageSummary = 'Maximum number of files exceeded, '; /** * Inline style of the element. * @group Props */ style; /** * Class of the element. * @group Props */ styleClass; /** * Width of the image thumbnail in pixels. * @group Props */ previewWidth = 50; /** * Label of the choose button. Defaults to PrimeNG Locale configuration. * @group Props */ chooseLabel; /** * Label of the upload button. Defaults to PrimeNG Locale configuration. * @group Props */ uploadLabel; /** * Label of the cancel button. Defaults to PrimeNG Locale configuration. * @group Props */ cancelLabel; /** * Icon of the choose button. * @group Props */ chooseIcon; /** * Icon of the upload button. * @group Props */ uploadIcon; /** * Icon of the cancel button. * @group Props */ cancelIcon; /** * Whether to show the upload button. * @group Props */ showUploadButton = true; /** * Whether to show the cancel button. * @group Props */ showCancelButton = true; /** * Defines the UI of the component. * @group Props */ mode = 'advanced'; /** * HttpHeaders class represents the header configuration options for an HTTP request. * @group Props */ headers; /** * Whether to use the default upload or a manual implementation defined in uploadHandler callback. Defaults to PrimeNG Locale configuration. * @group Props */ customUpload; /** * Maximum number of files that can be uploaded. * @group Props */ fileLimit; /** * Style class of the upload button. * @group Props */ uploadStyleClass; /** * Style class of the cancel button. * @group Props */ cancelStyleClass; /** * Style class of the remove button. * @group Props */ removeStyleClass; /** * Style class of the choose button. * @group Props */ chooseStyleClass; /** * Used to pass all properties of the ButtonProps to the choose button inside the component. * @group Props */ chooseButtonProps; /** * Used to pass all properties of the ButtonProps to the upload button inside the component. * @group Props */ uploadButtonProps = { severity: 'secondary' }; /** * Used to pass all properties of the ButtonProps to the cancel button inside the component. * @group Props */ cancelButtonProps = { severity: 'secondary' }; /** * Callback to invoke before file upload is initialized. * @param {FileBeforeUploadEvent} event - Custom upload event. * @group Emits */ onBeforeUpload = new EventEmitter(); /** * An event indicating that the request was sent to the server. Useful when a request may be retried multiple times, to distinguish between retries on the final event stream. * @param {FileSendEvent} event - Custom send event. * @group Emits */ onSend = new EventEmitter(); /** * Callback to invoke when file upload is complete. * @param {FileUploadEvent} event - Custom upload event. * @group Emits */ onUpload = new EventEmitter(); /** * Callback to invoke if file upload fails. * @param {FileUploadErrorEvent} event - Custom error event. * @group Emits */ onError = new EventEmitter(); /** * Callback to invoke when files in queue are removed without uploading using clear all button. * @param {Event} event - Browser event. * @group Emits */ onClear = new EventEmitter(); /** * Callback to invoke when a file is removed without uploading using clear button of a file. * @param {FileRemoveEvent} event - Remove event. * @group Emits */ onRemove = new EventEmitter(); /** * Callback to invoke when files are selected. * @param {FileSelectEvent} event - Select event. * @group Emits */ onSelect = new EventEmitter(); /** * Callback to invoke when files are being uploaded. * @param {FileProgressEvent} event - Progress event. * @group Emits */ onProgress = new EventEmitter(); /** * Callback to invoke in custom upload mode to upload the files manually. * @param {FileUploadHandlerEvent} event - Upload handler event. * @group Emits */ uploadHandler = new EventEmitter(); /** * This event is triggered if an error occurs while loading an image file. * @param {Event} event - Browser event. * @group Emits */ onImageError = new EventEmitter(); /** * This event is triggered if an error occurs while loading an image file. * @param {RemoveUploadedFileEvent} event - Remove event. * @group Emits */ onRemoveUploadedFile = new EventEmitter(); /** * Template for file. * @group Templates */ fileTemplate; /** * Template for header. * @group Templates */ headerTemplate; /** * Template for content. * @group Templates */ contentTemplate; /** * Template for toolbar. * @group Templates */ toolbarTemplate; /** * Template for choose icon. * @group Templates */ chooseIconTemplate; /** * Template for file label. * @group Templates */ fileLabelTemplate; /** * Template for upload icon. * @group Templates */ uploadIconTemplate; /** * Template for cancel icon. * @group Templates */ cancelIconTemplate; /** * Template for empty state. * @group Templates */ emptyTemplate; advancedFileInput; basicFileInput; content; set files(files) { this._files = []; for (let i = 0; i < files.length; i++) { let file = files[i]; if (this.validate(file)) { if (this.isImage(file)) { file.objectURL = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(files[i])); } this._files.push(files[i]); } } } get files() { return this._files; } get basicButtonLabel() { if (this.auto || !this.hasFiles()) { return this.chooseLabel; } return this.uploadLabel ?? this.files[0].name; } _files = []; progress = 0; dragHighlight; msgs; uploadedFileCount = 0; focus; uploading; duplicateIEEvent; // flag to recognize duplicate onchange event for file input translationSubscription; dragOverListener; uploadedFiles = []; sanitizer = inject(DomSanitizer); zone = inject(NgZone); http = inject(HttpClient); _componentStyle = inject(FileUploadStyle); ngOnInit() { super.ngOnInit(); this.translationSubscription = this.config.translationObserver.subscribe(() => { this.cd.markForCheck(); }); } ngAfterViewInit() { super.ngAfterViewInit(); if (isPlatformBrowser(this.platformId)) { if (this.mode === 'advanced') { this.zone.runOutsideAngular(() => { if (this.content) { this.dragOverListener = this.renderer.listen(this.content.nativeElement, 'dragover', this.onDragOver.bind(this)); } }); } } } _headerTemplate; _contentTemplate; _toolbarTemplate; _chooseIconTemplate; _uploadIconTemplate; _cancelIconTemplate; _emptyTemplate; _fileTemplate; _fileLabelTemplate; templates; ngAfterContentInit() { this.templates?.forEach((item) => { switch (item.getType()) { case 'header': this._headerTemplate = item.template; break; case 'file': this._fileTemplate = item.template; break; case 'content': this._contentTemplate = item.template; break; case 'toolbar': this._toolbarTemplate = item.template; break; case 'chooseicon': this._chooseIconTemplate = item.template; break; case 'uploadicon': this._uploadIconTemplate = item.template; break; case 'cancelicon': this._cancelIconTemplate = item.template; break; case 'empty': this._emptyTemplate = item.template; break; case 'filelabel': this._fileLabelTemplate = item.template; break; default: this._fileTemplate = item.template; break; } }); } basicFileChosenLabel() { if (this.auto) return this.chooseButtonLabel; else if (this.hasFiles()) { if (this.files && this.files.length === 1) return this.files[0].name; return this.config.getTranslation('fileChosenMessage')?.replace('{0}', this.files.length); } return this.config.getTranslation('noFileChosenMessage') || ''; } getTranslation(option) { return this.config.getTranslation(option); } choose() { this.advancedFileInput?.nativeElement.click(); } onFileSelect(event) { if (event.type !== 'drop' && this.isIE11() && this.duplicateIEEvent) { this.duplicateIEEvent = false; return; } this.msgs = []; if (!this.multiple) { this.files = []; } let files = event.dataTransfer ? event.dataTransfer.files : event.target.files; for (let i = 0; i < files.length; i++) { let file = files[i]; if (!this.isFileSelected(file)) { if (this.validate(file)) { if (this.isImage(file)) { file.objectURL = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(files[i])); } this.files.push(files[i]); } } } this.onSelect.emit({ originalEvent: event, files: files, currentFiles: this.files }); // this will check the fileLimit with the uploaded files this.checkFileLimit(files); if (this.hasFiles() && this.auto && (this.mode !== 'advanced' || !this.isFileLimitExceeded())) { this.upload(); } if (event.type !== 'drop' && this.isIE11()) { this.clearIEInput(); } else { this.clearInputElement(); } } isFileSelected(file) { for (let sFile of this.files) { if (sFile.name + sFile.type + sFile.size === file.name + file.type + file.size) { return true; } } return false; } isIE11() { if (isPlatformBrowser(this.platformId)) { return !!this.document.defaultView['MSInputMethodContext'] && !!this.document['documentMode']; } } validate(file) { this.msgs = this.msgs || []; if (this.accept && !this.isFileTypeValid(file)) { const text = `${this.invalidFileTypeMessageSummary.replace('{0}', file.name)} ${this.invalidFileTypeMessageDetail.replace('{0}', this.accept)}`; this.msgs.push({ severity: 'error', text: text }); return false; } if (this.maxFileSize && file.size > this.maxFileSize) { const text = `${this.invalidFileSizeMessageSummary.replace('{0}', file.name)} ${this.invalidFileSizeMessageDetail.replace('{0}', this.formatSize(this.maxFileSize))}`; this.msgs.push({ severity: 'error', text: text }); return false; } return true; } isFileTypeValid(file) { let acceptableTypes = this.accept?.split(',').map((type) => type.trim()); for (let type of acceptableTypes) { let acceptable = this.isWildcard(type) ? this.getTypeClass(file.type) === this.getTypeClass(type) : file.type == type || this.getFileExtension(file).toLowerCase() === type.toLowerCase(); if (acceptable) { return true; } } return false; } getTypeClass(fileType) { return fileType.substring(0, fileType.indexOf('/')); } isWildcard(fileType) { return fileType.indexOf('*') !== -1; } getFileExtension(file) { return '.' + file.name.split('.').pop(); } isImage(file) { return /^image\//.test(file.type); } onImageLoad(img) { window.URL.revokeObjectURL(img.src); } /** * Uploads the selected files. * @group Method */ uploader() { if (this.customUpload) { if (this.fileLimit) { this.uploadedFileCount += this.files.length; } this.uploadHandler.emit({ files: this.files }); this.cd.markForCheck(); } else { this.uploading = true; this.msgs = []; let formData = new FormData(); this.onBeforeUpload.emit({ formData: formData }); for (let i = 0; i < this.files.length; i++) { formData.append(this.name, this.files[i], this.files[i].name); } this.http .request(this.method, this.url, { body: formData, headers: this.headers, reportProgress: true, observe: 'events', withCredentials: this.withCredentials }) .subscribe((event) => { switch (event.type) { case HttpEventType.Sent: this.onSend.emit({ originalEvent: event, formData: formData }); break; case HttpEventType.Response: this.uploading = false; this.progress = 0; if (event['status'] >= 200 && event['status'] < 300) { if (this.fileLimit) { this.uploadedFileCount += this.files.length; } this.onUpload.emit({ originalEvent: event, files: this.files }); } else { this.onError.emit({ files: this.files }); } this.uploadedFiles.push(...this.files); this.clear(); break; case HttpEventType.UploadProgress: { if (event['loaded']) { this.progress = Math.round((event['loaded'] * 100) / event['total']); } this.onProgress.emit({ originalEvent: event, progress: this.progress }); break; } } this.cd.markForCheck(); }, (error) => { this.uploading = false; this.onError.emit({ files: this.files, error: error }); }); } } /** * Clears the files list. * @group Method */ clear() { this.files = []; this.uploadedFileCount = 0; this.onClear.emit(); this.clearInputElement(); this.msgs = []; this.cd.markForCheck(); } /** * Removes a single file. * @param {Event} event - Browser event. * @param {Number} index - Index of the file. * @group Method */ remove(event, index) { this.clearInputElement(); this.onRemove.emit({ originalEvent: event, file: this.files[index] }); this.files.splice(index, 1); this.checkFileLimit(this.files); } /** * Removes uploaded file. * @param {Number} index - Index of the file to be removed. * @group Method */ removeUploadedFile(index) { let removedFile = this.uploadedFiles.splice(index, 1)[0]; this.uploadedFiles = [...this.uploadedFiles]; this.onRemoveUploadedFile.emit({ file: removedFile, files: this.uploadedFiles }); } isFileLimitExceeded() { const isAutoMode = this.auto; const totalFileCount = isAutoMode ? this.files.length : this.files.length + this.uploadedFileCount; if (this.fileLimit && this.fileLimit <= totalFileCount && this.focus) { this.focus = false; } return this.fileLimit && this.fileLimit < totalFileCount; } isChooseDisabled() { if (this.auto) { return this.fileLimit && this.fileLimit <= this.files.length; } else { return this.fileLimit && this.fileLimit <= this.files.length + this.uploadedFileCount; } } checkFileLimit(files) { this.msgs ??= []; const hasExistingValidationMessages = this.msgs.length > 0 && this.fileLimit && this.fileLimit < files.length; if (this.isFileLimitExceeded() || hasExistingValidationMessages) { const text = `${this.invalidFileLimitMessageSummary.replace('{0}', this.fileLimit.toString())} ${this.invalidFileLimitMessageDetail.replace('{0}', this.fileLimit.toString())}`; this.msgs.push({ severity: 'error', text: text }); } else { this.msgs = this.msgs.filter((msg) => !msg.text.includes(this.invalidFileLimitMessageSummary)); } } clearInputElement() { if (this.advancedFileInput && this.advancedFileInput.nativeElement) { this.advancedFileInput.nativeElement.value = ''; } if (this.basicFileInput && this.basicFileInput.nativeElement) { this.basicFileInput.nativeElement.value = ''; } } clearIEInput() { if (this.advancedFileInput && this.advancedFileInput.nativeElement) { this.duplicateIEEvent = true; //IE11 fix to prevent onFileChange trigger again this.advancedFileInput.nativeElement.value = ''; } } hasFiles() { return this.files && this.files.length > 0; } hasUploadedFiles() { return this.uploadedFiles && this.uploadedFiles.length > 0; } onDragEnter(e) { if (!this.disabled) { e.stopPropagation(); e.preventDefault(); } } onDragOver(e) { if (!this.disabled) { addClass(this.content?.nativeElement, 'p-fileupload-highlight'); this.dragHighlight = true; e.stopPropagation(); e.preventDefault(); } } onDragLeave(event) { if (!this.disabled) { removeClass(this.content?.nativeElement, 'p-fileupload-highlight'); } } onDrop(event) { if (!this.disabled) { removeClass(this.content?.nativeElement, 'p-fileupload-highlight'); event.stopPropagation(); event.preventDefault(); let files = event.dataTransfer ? event.dataTransfer.files : event.target.files; let allowDrop = this.multiple || (files && files.length === 1); if (allowDrop) { this.onFileSelect(event); } } } onFocus() { this.focus = true; } onBlur() { this.focus = false; } formatSize(bytes) { const k = 1024; const dm = 3; const sizes = this.getTranslation(TranslationKeys.FILE_SIZE_TYPES); if (bytes === 0) { return `0 ${sizes[0]}`; } const i = Math.floor(Math.log(bytes) / Math.log(k)); const formattedSize = (bytes / Math.pow(k, i)).toFixed(dm); return `${formattedSize} ${sizes[i]}`; } upload() { if (this.hasFiles()) this.uploader(); } onBasicUploaderClick() { this.basicFileInput?.nativeElement.click(); } onBasicKeydown(event) { switch (event.code) { case 'Space': case 'Enter': this.onBasicUploaderClick(); event.preventDefault(); break; } } imageError(event) { this.onImageError.emit(event); } getBlockableElement() { return this.el.nativeElement.children[0]; } get chooseButtonLabel() { return this.chooseLabel || this.config.getTranslation(TranslationKeys.CHOOSE); } get uploadButtonLabel() { return this.uploadLabel || this.config.getTranslation(TranslationKeys.UPLOAD); } get cancelButtonLabel() { return this.cancelLabel || this.config.getTranslation(TranslationKeys.CANCEL); } get browseFilesLabel() { return this.config.getTranslation(TranslationKeys.ARIA)[TranslationKeys.BROWSE_FILES]; } get pendingLabel() { return this.config.getTranslation(TranslationKeys.PENDING); } ngOnDestroy() { if (this.content && this.content.nativeElement) { if (this.dragOverListener) { this.dragOverListener(); this.dragOverListener = null; } } if (this.translationSubscription) { this.translationSubscription.unsubscribe(); } super.ngOnDestroy(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: FileUpload, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.10", type: FileUpload, isStandalone: true, selector: "p-fileupload, p-fileUpload", inputs: { name: "name", url: "url", method: "method", multiple: ["multiple", "multiple", booleanAttribute], accept: "accept", disabled: ["disabled", "disabled", booleanAttribute], auto: ["auto", "auto", booleanAttribute], withCredentials: ["withCredentials", "withCredentials", booleanAttribute], maxFileSize: ["maxFileSize", "maxFileSize", numberAttribute], invalidFileSizeMessageSummary: "invalidFileSizeMessageSummary", invalidFileSizeMessageDetail: "invalidFileSizeMessageDetail", invalidFileTypeMessageSummary: "invalidFileTypeMessageSummary", invalidFileTypeMessageDetail: "invalidFileTypeMessageDetail", invalidFileLimitMessageDetail: "invalidFileLimitMessageDetail", invalidFileLimitMessageSummary: "invalidFileLimitMessageSummary", style: "style", styleClass: "styleClass", previewWidth: ["previewWidth", "previewWidth", numberAttribute], chooseLabel: "chooseLabel", uploadLabel: "uploadLabel", cancelLabel: "cancelLabel", chooseIcon: "chooseIcon", uploadIcon: "uploadIcon", cancelIcon: "cancelIcon", showUploadButton: ["showUploadButton", "showUploadButton", booleanAttribute], showCancelButton: ["showCancelButton", "showCancelButton", booleanAttribute], mode: "mode", headers: "headers", customUpload: ["customUpload", "customUpload", booleanAttribute], fileLimit: ["fileLimit", "fileLimit", (value) => numberAttribute(value, null)], uploadStyleClass: "uploadStyleClass", cancelStyleClass: "cancelStyleClass", removeStyleClass: "removeStyleClass", chooseStyleClass: "chooseStyleClass", chooseButtonProps: "chooseButtonProps", uploadButtonProps: "uploadButtonProps", cancelButtonProps: "cancelButtonProps", files: "files" }, outputs: { onBeforeUpload: "onBeforeUpload", onSend: "onSend", onUpload: "onUpload", onError: "onError", onClear: "onClear", onRemove: "onRemove", onSelect: "onSelect", onProgress: "onProgress", uploadHandler: "uploadHandler", onImageError: "onImageError", onRemoveUploadedFile: "onRemoveUploadedFile" }, providers: [FileUploadStyle], queries: [{ propertyName: "fileTemplate", first: true, predicate: ["file"] }, { propertyName: "headerTemplate", first: true, predicate: ["header"] }, { propertyName: "contentTemplate", first: true, predicate: ["content"] }, { propertyName: "toolbarTemplate", first: true, predicate: ["toolbar"] }, { propertyName: "chooseIconTemplate", first: true, predicate: ["chooseicon"] }, { propertyName: "fileLabelTemplate", first: true, predicate: ["filelabel"] }, { propertyName: "uploadIconTemplate", first: true, predicate: ["uploadicon"] }, { propertyName: "cancelIconTemplate", first: true, predicate: ["cancelicon"] }, { propertyName: "emptyTemplate", first: true, predicate: ["empty"] }, { propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "advancedFileInput", first: true, predicate: ["advancedfileinput"], descendants: true }, { propertyName: "basicFileInput", first: true, predicate: ["basicfileinput"], descendants: true }, { propertyName: "content", first: true, predicate: ["content"], descendants: true }], usesInheritance: true, ngImport: i0, template: ` <div [ngClass]="'p-fileupload p-fileupload-advanced p-component'" [ngStyle]="style" [class]="styleClass" *ngIf="mode === 'advanced'" [attr.data-pc-name]="'fileupload'" [attr.data-pc-section]="'root'"> <input [attr.aria-label]="browseFilesLabel" #advancedfileinput type="file" (change)="onFileSelect($event)" [multiple]="multiple" [accept]="accept" [disabled]="disabled || isChooseDisabled()" [attr.title]="''" [attr.data-pc-section]="'input'" [style.display]="'none'" /> <div class="p-fileupload-header"> <ng-container *ngIf="!headerTemplate && !_headerTemplate"> <p-button [styleClass]="'p-fileupload-choose-button ' + chooseStyleClass" [disabled]="disabled || isChooseDisabled()" (focus)="onFocus()" [label]="chooseButtonLabel" (blur)="onBlur()" (onClick)="choose()" (keydown.enter)="choose()" [attr.data-pc-section]="'choosebutton'" [buttonProps]="chooseButtonProps" > <input [attr.aria-label]="browseFilesLabel" #advancedfileinput type="file" (change)="onFileSelect($event)" [multiple]="multiple" [accept]="accept" [disabled]="disabled || isChooseDisabled()" [attr.title]="''" [attr.data-pc-section]="'input'" /> <span *ngIf="chooseIcon" [class]="chooseIcon" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon *ngIf="!chooseIconTemplate && !_chooseIconTemplate" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'" /> <span *ngIf="chooseIconTemplate || _chooseIconTemplate" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"> <ng-template *ngTemplateOutlet="chooseIconTemplate || _chooseIconTemplate"></ng-template> </span> </ng-container> </p-button> <p-button *ngIf="!auto && showUploadButton" [label]="uploadButtonLabel" (onClick)="upload()" [disabled]="!hasFiles() || isFileLimitExceeded()" [styleClass]="'p-fileupload-upload-button ' + uploadStyleClass" [buttonProps]="uploadButtonProps" > <span *ngIf="uploadIcon" [ngClass]="uploadIcon" [attr.aria-hidden]="true"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate && !_uploadIconTemplate" /> <span *ngIf="uploadIconTemplate || _uploadIconTemplate" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="uploadIconTemplate || _uploadIconTemplate"></ng-template> </span> </ng-container> </p-button> <p-button *ngIf="!auto && showCancelButton" [label]="cancelButtonLabel" (onClick)="clear()" [disabled]="!hasFiles() || uploading" [styleClass]="'p-fileupload-cancel-button ' + cancelStyleClass" [buttonProps]="cancelButtonProps"> <span *ngIf="cancelIcon" [ngClass]="cancelIcon"></span> <ng-container *ngIf="!cancelIcon"> <TimesIcon *ngIf="!cancelIconTemplate && !_cancelIconTemplate" [attr.aria-hidden]="true" /> <span *ngIf="cancelIconTemplate || _cancelIconTemplate" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="cancelIconTemplate || _cancelIconTemplate"></ng-template> </span> </ng-container> </p-button> </ng-container> <ng-container *ngTemplateOutlet=" headerTemplate || _headerTemplate; context: { $implicit: files, uploadedFiles: uploadedFiles, chooseCallback: choose.bind(this), clearCallback: clear.bind(this), uploadCallback: upload.bind(this) } " ></ng-container> <ng-container *ngTemplateOutlet="toolbarTemplate || _toolbarTemplate"></ng-container> </div> <div #content class="p-fileupload-content" (dragenter)="onDragEnter($event)" (dragleave)="onDragLeave($event)" (drop)="onDrop($event)" [attr.data-pc-section]="'content'"> <p-progressbar [value]="progress" [showValue]="false" *ngIf="hasFiles()"></p-progressbar> @for (message of msgs; track message) { <p-message [severity]="message.severity" [text]="message.text"></p-message> } <div class="p-fileupload-file-list" *ngIf="hasFiles()"> @if (!fileTemplate && !_fileTemplate) { <div class="p-fileupload-file" *ngFor="let file of files; let i = index"> <img [src]="file.objectURL" *ngIf="isImage(file)" [width]="previewWidth" (error)="imageError($event)" class="p-fileupload-file-thumbnail" /> <div class="p-fileupload-file-info"> <div class="p-fileupload-file-name">{{ file.name }}</div> <span class="p-fileupload-file-size">{{ formatSize(file.size) }}</span> </div> <div class="p-fileupload-file-actions"> <p-button (onClick)="remove($event, i)" [disabled]="uploading" text rounded severity="danger" [styleClass]="'p-fileupload-file-remove-button ' + removeStyleClass"> <ng-template #icon> <TimesIcon *ngIf="!cancelIconTemplate && !_cancelIconTemplate" /> <ng-template *ngTemplateOutlet="cancelIconTemplate || _cancelIconTemplate"></ng-template> </ng-template> </p-button> </div> </div> } @if (fileTemplate || _fileTemplate) { <ng-template ngFor [ngForOf]="files" [ngForTemplate]="fileTemplate || _fileTemplate"></ng-template> } </div> <ng-container *ngTemplateOutlet=" contentTemplate || _contentTemplate; context: { $implicit: files, uploadedFiles: uploadedFiles, chooseCallback: choose.bind(this), clearCallback: clear.bind(this), removeUploadedFileCallback: removeUploadedFile.bind(this), removeFileCallback: remove.bind(this), progress: progress, messages: msgs } " ></ng-container> @if ((emptyTemplate || _emptyTemplate) && !hasFiles() && !hasUploadedFiles()) { <ng-container *ngTemplateOutlet="emptyTemplate || _emptyTemplate"></ng-container> } </div> </div> <div [ngClass]="'p-fileupload p-fileupload-basic p-component'" [class]="styleClass" *ngIf="mode === 'basic'" [attr.data-pc-name]="'fileupload'"> @for (message of msgs; track message) { <p-message [severity]="message.severity" [text]="message.text"></p-message> } <p-button [styleClass]="'p-fileupload-choose-button ' + chooseStyleClass" [disabled]="disabled" [label]="chooseButtonLabel" [style]="style" (onClick)="onBasicUploaderClick()" (keydown)="onBasicKeydown($event)" [buttonProps]="chooseButtonProps" > <ng-template #icon> @if (hasFiles() && !auto) { <span *ngIf="uploadIcon" class="p-button-icon p-button-icon-left" [ngClass]="uploadIcon"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate && !_uploadIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" /> <span *ngIf="_uploadIconTemplate || uploadIconTemplate" class="p-button-icon p-button-icon-left"> <ng-template *ngTemplateOutlet="_uploadIconTemplate || uploadIconTemplate"></ng-template> </span> </ng-container> } @else { <span *ngIf="chooseIcon" class="p-button-icon p-button-icon-left pi" [ngClass]="chooseIcon"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon *ngIf="!chooseIconTemplate && !_chooseIconTemplate" [attr.data-pc-section]="'uploadicon'" /> <ng-template *ngTemplateOutlet="chooseIconTemplate || _chooseIconTemplate"></ng-template> </ng-container> } </ng-template> <input [attr.aria-label]="browseFilesLabel" #basicfileinput type="file" [accept]="accept" [multiple]="multiple" [disabled]="disabled" (change)="onFileSelect($event)" (focus)="onFocus()" (blur)="onBlur()" [attr.data-pc-section]="'input'" /> </p-button> @if (!auto) { @if (!fileLabelTemplate && !_fileLabelTemplate) { <span [class]="cx('filelabel')"> {{ basicFileChosenLabel() }} </span> } @else { <ng-container *ngTemplateOutlet="fileLabelTemplate || _fileLabelTemplate; context: { $implicit: files }"></ng-container> } } </div> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "component", type: PlusIcon, selector: "PlusIcon" }, { kind: "component", type: UploadIcon, selector: "UploadIcon" }, { kind: "component", type: TimesIcon, selector: "TimesIcon" }, { kind: "ngmodule", type: SharedModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.10", ngImport: i0, type: FileUpload, decorators: [{ type: Component, args: [{ selector: 'p-fileupload, p-fileUpload', standalone: true, imports: [CommonModule, Button, ProgressBar, Message, PlusIcon, UploadIcon, TimesIcon, SharedModule], template: ` <div [ngClass]="'p-fileupload p-fileupload-advanced p-component'" [ngStyle]="style" [class]="styleClass" *ngIf="mode === 'advanced'" [attr.data-pc-name]="'fileupload'" [attr.data-pc-section]="'root'"> <input [attr.aria-label]="browseFilesLabel" #advancedfileinput type="file" (change)="onFileSelect($event)" [multiple]="multiple" [accept]="accept" [disabled]="disabled || isChooseDisabled()" [attr.title]="''" [attr.data-pc-section]="'input'" [style.display]="'none'" /> <div class="p-fileupload-header"> <ng-container *ngIf="!headerTemplate && !_headerTemplate"> <p-button [styleClass]="'p-fileupload-choose-button ' + chooseStyleClass" [disabled]="disabled || isChooseDisabled()" (focus)="onFocus()" [label]="chooseButtonLabel" (blur)="onBlur()" (onClick)="choose()" (keydown.enter)="choose()" [attr.data-pc-section]="'choosebutton'" [buttonProps]="chooseButtonProps" > <input [attr.aria-label]="browseFilesLabel" #advancedfileinput type="file" (change)="onFileSelect($event)" [multiple]="multiple" [accept]="accept" [disabled]="disabled || isChooseDisabled()" [attr.title]="''" [attr.data-pc-section]="'input'" /> <span *ngIf="chooseIcon" [class]="chooseIcon" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon *ngIf="!chooseIconTemplate && !_chooseIconTemplate" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'" /> <span *ngIf="chooseIconTemplate || _chooseIconTemplate" [attr.aria-label]="true" [attr.data-pc-secti