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 lines 75.7 kB
{"version":3,"file":"primeng-fileupload.mjs","sources":["../../src/fileupload/style/fileuploadstyle.ts","../../src/fileupload/fileupload.ts","../../src/fileupload/primeng-fileupload.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { BaseStyle } from 'primeng/base';\n\nconst theme = ({ dt }) => `\n.p-fileupload input[type=\"file\"] {\n display: none;\n}\n\n.p-fileupload-advanced {\n border: 1px solid ${dt('fileupload.border.color')};\n border-radius: ${dt('fileupload.border.radius')};\n background: ${dt('fileupload.background')};\n color: ${dt('fileupload.color')};\n}\n\n.p-fileupload-header {\n display: flex;\n align-items: center;\n padding: ${dt('fileupload.header.padding')};\n background: ${dt('fileupload.header.background')};\n color: ${dt('fileupload.header.color')};\n border-style: solid;\n border-width: ${dt('fileupload.header.border.width')};\n border-color: ${dt('fileupload.header.border.color')};\n border-radius: ${dt('fileupload.header.border.radius')};\n gap: ${dt('fileupload.header.gap')};\n}\n\n.p-fileupload-content {\n border: 1px solid transparent;\n display: flex;\n flex-direction: column;\n gap: ${dt('fileupload.content.gap')};\n transition: border-color ${dt('fileupload.transition.duration')};\n padding: ${dt('fileupload.content.padding')};\n}\n\n.p-fileupload-content .p-progressbar {\n width: 100%;\n height: ${dt('fileupload.progressbar.height')};\n}\n\n.p-fileupload-file-list {\n display: flex;\n flex-direction: column;\n gap: ${dt('fileupload.filelist.gap')};\n}\n\n.p-fileupload-file {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n padding: ${dt('fileupload.file.padding')};\n border-bottom: 1px solid ${dt('fileupload.file.border.color')};\n gap: ${dt('fileupload.file.gap')};\n}\n\n.p-fileupload-file:last-child {\n border-bottom: 0;\n}\n\n.p-fileupload-file-info {\n display: flex;\n flex-direction: column;\n gap: ${dt('fileupload.file.info.gap')};\n}\n\n.p-fileupload-file-thumbnail {\n flex-shrink: 0;\n}\n\n.p-fileupload-file-actions {\n margin-left: auto;\n}\n\n.p-fileupload-highlight {\n border: 1px dashed ${dt('fileupload.content.highlight.border.color')};\n}\n\n.p-fileupload-advanced .p-message {\n margin-top: 0;\n}\n\n.p-fileupload-basic {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: center;\n gap: ${dt('fileupload.basic.gap')};\n}\n`;\n\nconst classes = {\n root: ({ instance }) => `p-fileupload p-fileupload-${instance.mode} p-component`,\n header: 'p-fileupload-header',\n pcChooseButton: 'p-fileupload-choose-button',\n pcUploadButton: 'p-fileupload-upload-button',\n pcCancelButton: 'p-fileupload-cancel-button',\n content: 'p-fileupload-content',\n fileList: 'p-fileupload-file-list',\n file: 'p-fileupload-file',\n fileThumbnail: 'p-fileupload-file-thumbnail',\n fileInfo: 'p-fileupload-file-info',\n fileName: 'p-fileupload-file-name',\n fileSize: 'p-fileupload-file-size',\n pcFileBadge: 'p-fileupload-file-badge',\n fileActions: 'p-fileupload-file-actions',\n pcFileRemoveButton: 'p-fileupload-file-remove-button'\n};\n\n@Injectable()\nexport class FileUploadStyle extends BaseStyle {\n name = 'fileupload';\n\n theme = theme;\n\n classes = classes;\n}\n\n/**\n *\n * FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations.\n *\n * [Live Demo](https://www.primeng.org/fileupload/)\n *\n * @module fileuploadstyle\n *\n */\n\nexport enum FileUploadClasses {\n /**\n * Class name of the root element\n */\n root = 'p-fileupload',\n /**\n * Class name of the header element\n */\n header = 'p-fileupload-header',\n /**\n * Class name of the choose button element\n */\n pcChooseButton = 'p-fileupload-choose-button',\n /**\n * Class name of the upload button element\n */\n pcUploadButton = 'p-fileupload-upload-button',\n /**\n * Class name of the cancel button element\n */\n pcCancelButton = 'p-fileupload-cancel-button',\n /**\n * Class name of the content element\n */\n content = 'p-fileupload-content',\n /**\n * Class name of the file list element\n */\n fileList = 'p-fileupload-file-list',\n /**\n * Class name of the file element\n */\n file = 'p-fileupload-file',\n /**\n * Class name of the file thumbnail element\n */\n fileThumbnail = 'p-fileupload-file-thumbnail',\n /**\n * Class name of the file info element\n */\n fileInfo = 'p-fileupload-file-info',\n /**\n * Class name of the file name element\n */\n fileName = 'p-fileupload-file-name',\n /**\n * Class name of the file size element\n */\n fileSize = 'p-fileupload-file-size',\n /**\n * Class name of the file badge element\n */\n pcFileBadge = 'p-fileupload-file-badge',\n /**\n * Class name of the file actions element\n */\n fileActions = 'p-fileupload-file-actions',\n /**\n * Class name of the file remove button element\n */\n pcFileRemoveButton = 'p-fileupload-file-remove-button'\n}\n\nexport interface FileUploadStyle extends BaseStyle {}\n","import { CommonModule, isPlatformBrowser } from '@angular/common';\nimport { HttpClient, HttpEvent, HttpEventType, HttpHeaders } from '@angular/common/http';\nimport {\n AfterContentInit,\n AfterViewInit,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n ContentChild,\n ContentChildren,\n ElementRef,\n EventEmitter,\n inject,\n Input,\n NgModule,\n NgZone,\n numberAttribute,\n OnDestroy,\n OnInit,\n Output,\n QueryList,\n TemplateRef,\n ViewChild,\n ViewEncapsulation\n} from '@angular/core';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport { addClass, removeClass } from '@primeuix/utils';\nimport { BlockableUI, PrimeTemplate, SharedModule, TranslationKeys } from 'primeng/api';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport { Button, ButtonProps } from 'primeng/button';\nimport { PlusIcon, TimesIcon, UploadIcon } from 'primeng/icons';\nimport { Message } from 'primeng/message';\nimport { ProgressBar } from 'primeng/progressbar';\nimport { VoidListener } from 'primeng/ts-helpers';\nimport { Subscription } from 'rxjs';\nimport { FileBeforeUploadEvent, FileProgressEvent, FileRemoveEvent, FileSelectEvent, FileSendEvent, FileUploadErrorEvent, FileUploadEvent, FileUploadHandlerEvent, RemoveUploadedFileEvent } from './fileupload.interface';\nimport { FileUploadStyle } from './style/fileuploadstyle';\n\n/**\n * FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations.\n * @group Components\n */\n@Component({\n selector: 'p-fileupload, p-fileUpload',\n standalone: true,\n imports: [CommonModule, Button, ProgressBar, Message, PlusIcon, UploadIcon, TimesIcon, SharedModule],\n template: `\n <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'\">\n <input\n [attr.aria-label]=\"browseFilesLabel\"\n #advancedfileinput\n type=\"file\"\n (change)=\"onFileSelect($event)\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n [disabled]=\"disabled || isChooseDisabled()\"\n [attr.title]=\"''\"\n [attr.data-pc-section]=\"'input'\"\n [style.display]=\"'none'\"\n />\n <div class=\"p-fileupload-header\">\n <ng-container *ngIf=\"!headerTemplate && !_headerTemplate\">\n <p-button\n [styleClass]=\"'p-fileupload-choose-button ' + chooseStyleClass\"\n [disabled]=\"disabled || isChooseDisabled()\"\n (focus)=\"onFocus()\"\n [label]=\"chooseButtonLabel\"\n (blur)=\"onBlur()\"\n (onClick)=\"choose()\"\n (keydown.enter)=\"choose()\"\n [attr.data-pc-section]=\"'choosebutton'\"\n [buttonProps]=\"chooseButtonProps\"\n >\n <input\n [attr.aria-label]=\"browseFilesLabel\"\n #advancedfileinput\n type=\"file\"\n (change)=\"onFileSelect($event)\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n [disabled]=\"disabled || isChooseDisabled()\"\n [attr.title]=\"''\"\n [attr.data-pc-section]=\"'input'\"\n />\n <span *ngIf=\"chooseIcon\" [class]=\"chooseIcon\" [attr.aria-label]=\"true\" [attr.data-pc-section]=\"'chooseicon'\"></span>\n <ng-container *ngIf=\"!chooseIcon\">\n <PlusIcon *ngIf=\"!chooseIconTemplate && !_chooseIconTemplate\" [attr.aria-label]=\"true\" [attr.data-pc-section]=\"'chooseicon'\" />\n <span *ngIf=\"chooseIconTemplate || _chooseIconTemplate\" [attr.aria-label]=\"true\" [attr.data-pc-section]=\"'chooseicon'\">\n <ng-template *ngTemplateOutlet=\"chooseIconTemplate || _chooseIconTemplate\"></ng-template>\n </span>\n </ng-container>\n </p-button>\n\n <p-button\n *ngIf=\"!auto && showUploadButton\"\n [label]=\"uploadButtonLabel\"\n (onClick)=\"upload()\"\n [disabled]=\"!hasFiles() || isFileLimitExceeded()\"\n [styleClass]=\"'p-fileupload-upload-button ' + uploadStyleClass\"\n [buttonProps]=\"uploadButtonProps\"\n >\n <span *ngIf=\"uploadIcon\" [ngClass]=\"uploadIcon\" [attr.aria-hidden]=\"true\"></span>\n <ng-container *ngIf=\"!uploadIcon\">\n <UploadIcon *ngIf=\"!uploadIconTemplate && !_uploadIconTemplate\" />\n <span *ngIf=\"uploadIconTemplate || _uploadIconTemplate\" [attr.aria-hidden]=\"true\">\n <ng-template *ngTemplateOutlet=\"uploadIconTemplate || _uploadIconTemplate\"></ng-template>\n </span>\n </ng-container>\n </p-button>\n <p-button *ngIf=\"!auto && showCancelButton\" [label]=\"cancelButtonLabel\" (onClick)=\"clear()\" [disabled]=\"!hasFiles() || uploading\" [styleClass]=\"'p-fileupload-cancel-button ' + cancelStyleClass\" [buttonProps]=\"cancelButtonProps\">\n <span *ngIf=\"cancelIcon\" [ngClass]=\"cancelIcon\"></span>\n <ng-container *ngIf=\"!cancelIcon\">\n <TimesIcon *ngIf=\"!cancelIconTemplate && !_cancelIconTemplate\" [attr.aria-hidden]=\"true\" />\n <span *ngIf=\"cancelIconTemplate || _cancelIconTemplate\" [attr.aria-hidden]=\"true\">\n <ng-template *ngTemplateOutlet=\"cancelIconTemplate || _cancelIconTemplate\"></ng-template>\n </span>\n </ng-container>\n </p-button>\n </ng-container>\n <ng-container\n *ngTemplateOutlet=\"\n headerTemplate || _headerTemplate;\n context: {\n $implicit: files,\n uploadedFiles: uploadedFiles,\n chooseCallback: choose.bind(this),\n clearCallback: clear.bind(this),\n uploadCallback: upload.bind(this)\n }\n \"\n ></ng-container>\n <ng-container *ngTemplateOutlet=\"toolbarTemplate || _toolbarTemplate\"></ng-container>\n </div>\n <div #content class=\"p-fileupload-content\" (dragenter)=\"onDragEnter($event)\" (dragleave)=\"onDragLeave($event)\" (drop)=\"onDrop($event)\" [attr.data-pc-section]=\"'content'\">\n <p-progressbar [value]=\"progress\" [showValue]=\"false\" *ngIf=\"hasFiles()\"></p-progressbar>\n @for (message of msgs; track message) {\n <p-message [severity]=\"message.severity\" [text]=\"message.text\"></p-message>\n }\n\n <div class=\"p-fileupload-file-list\" *ngIf=\"hasFiles()\">\n @if (!fileTemplate && !_fileTemplate) {\n <div class=\"p-fileupload-file\" *ngFor=\"let file of files; let i = index\">\n <img [src]=\"file.objectURL\" *ngIf=\"isImage(file)\" [width]=\"previewWidth\" (error)=\"imageError($event)\" class=\"p-fileupload-file-thumbnail\" />\n <div class=\"p-fileupload-file-info\">\n <div class=\"p-fileupload-file-name\">{{ file.name }}</div>\n <span class=\"p-fileupload-file-size\">{{ formatSize(file.size) }}</span>\n </div>\n <div class=\"p-fileupload-file-actions\">\n <p-button (onClick)=\"remove($event, i)\" [disabled]=\"uploading\" text rounded severity=\"danger\" [styleClass]=\"'p-fileupload-file-remove-button ' + removeStyleClass\">\n <ng-template #icon>\n <TimesIcon *ngIf=\"!cancelIconTemplate && !_cancelIconTemplate\" />\n <ng-template *ngTemplateOutlet=\"cancelIconTemplate || _cancelIconTemplate\"></ng-template>\n </ng-template>\n </p-button>\n </div>\n </div>\n }\n @if (fileTemplate || _fileTemplate) {\n <ng-template ngFor [ngForOf]=\"files\" [ngForTemplate]=\"fileTemplate || _fileTemplate\"></ng-template>\n }\n </div>\n <ng-container\n *ngTemplateOutlet=\"\n contentTemplate || _contentTemplate;\n context: {\n $implicit: files,\n uploadedFiles: uploadedFiles,\n chooseCallback: choose.bind(this),\n clearCallback: clear.bind(this),\n removeUploadedFileCallback: removeUploadedFile.bind(this),\n removeFileCallback: remove.bind(this),\n progress: progress,\n messages: msgs\n }\n \"\n ></ng-container>\n @if ((emptyTemplate || _emptyTemplate) && !hasFiles() && !hasUploadedFiles()) {\n <ng-container *ngTemplateOutlet=\"emptyTemplate || _emptyTemplate\"></ng-container>\n }\n </div>\n </div>\n <div [ngClass]=\"'p-fileupload p-fileupload-basic p-component'\" [class]=\"styleClass\" *ngIf=\"mode === 'basic'\" [attr.data-pc-name]=\"'fileupload'\">\n @for (message of msgs; track message) {\n <p-message [severity]=\"message.severity\" [text]=\"message.text\"></p-message>\n }\n\n <p-button\n [styleClass]=\"'p-fileupload-choose-button ' + chooseStyleClass\"\n [disabled]=\"disabled\"\n [label]=\"chooseButtonLabel\"\n [style]=\"style\"\n (onClick)=\"onBasicUploaderClick()\"\n (keydown)=\"onBasicKeydown($event)\"\n [buttonProps]=\"chooseButtonProps\"\n >\n <ng-template #icon>\n @if (hasFiles() && !auto) {\n <span *ngIf=\"uploadIcon\" class=\"p-button-icon p-button-icon-left\" [ngClass]=\"uploadIcon\"></span>\n <ng-container *ngIf=\"!uploadIcon\">\n <UploadIcon *ngIf=\"!uploadIconTemplate && !_uploadIconTemplate\" [styleClass]=\"'p-button-icon p-button-icon-left'\" />\n <span *ngIf=\"_uploadIconTemplate || uploadIconTemplate\" class=\"p-button-icon p-button-icon-left\">\n <ng-template *ngTemplateOutlet=\"_uploadIconTemplate || uploadIconTemplate\"></ng-template>\n </span>\n </ng-container>\n } @else {\n <span *ngIf=\"chooseIcon\" class=\"p-button-icon p-button-icon-left pi\" [ngClass]=\"chooseIcon\"></span>\n <ng-container *ngIf=\"!chooseIcon\">\n <PlusIcon *ngIf=\"!chooseIconTemplate && !_chooseIconTemplate\" [attr.data-pc-section]=\"'uploadicon'\" />\n <ng-template *ngTemplateOutlet=\"chooseIconTemplate || _chooseIconTemplate\"></ng-template>\n </ng-container>\n }\n </ng-template>\n <input\n [attr.aria-label]=\"browseFilesLabel\"\n #basicfileinput\n type=\"file\"\n [accept]=\"accept\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n (change)=\"onFileSelect($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [attr.data-pc-section]=\"'input'\"\n />\n </p-button>\n @if (!auto) {\n @if (!fileLabelTemplate && !_fileLabelTemplate) {\n <span [class]=\"cx('filelabel')\">\n {{ basicFileChosenLabel() }}\n </span>\n } @else {\n <ng-container *ngTemplateOutlet=\"fileLabelTemplate || _fileLabelTemplate; context: { $implicit: files }\"></ng-container>\n }\n }\n </div>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [FileUploadStyle]\n})\nexport class FileUpload extends BaseComponent implements AfterViewInit, AfterContentInit, OnInit, OnDestroy, BlockableUI {\n /**\n * Name of the request parameter to identify the files at backend.\n * @group Props\n */\n @Input() name: string | undefined;\n /**\n * Remote url to upload the files.\n * @group Props\n */\n @Input() url: string | undefined;\n /**\n * HTTP method to send the files to the url such as \"post\" and \"put\".\n * @group Props\n */\n @Input() method: 'post' | 'put' | undefined = 'post';\n /**\n * Used to select multiple files at once from file dialog.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) multiple: boolean | undefined;\n /**\n * 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\").\n * @group Props\n */\n @Input() accept: string | undefined;\n /**\n * Disables the upload functionality.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) disabled: boolean | undefined;\n /**\n * When enabled, upload begins automatically after selection is completed.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) auto: boolean | undefined;\n /**\n * Cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) withCredentials: boolean | undefined;\n /**\n * Maximum file size allowed in bytes.\n * @group Props\n */\n @Input({ transform: numberAttribute }) maxFileSize: number | undefined;\n /**\n * Summary message of the invalid file size.\n * @group Props\n */\n @Input() invalidFileSizeMessageSummary: string = '{0}: Invalid file size, ';\n /**\n * Detail message of the invalid file size.\n * @group Props\n */\n @Input() invalidFileSizeMessageDetail: string = 'maximum upload size is {0}.';\n /**\n * Summary message of the invalid file type.\n * @group Props\n */\n @Input() invalidFileTypeMessageSummary: string = '{0}: Invalid file type, ';\n /**\n * Detail message of the invalid file type.\n * @group Props\n */\n @Input() invalidFileTypeMessageDetail: string = 'allowed file types: {0}.';\n /**\n * Detail message of the invalid file type.\n * @group Props\n */\n @Input() invalidFileLimitMessageDetail: string = 'limit is {0} at most.';\n /**\n * Summary message of the invalid file type.\n * @group Props\n */\n @Input() invalidFileLimitMessageSummary: string = 'Maximum number of files exceeded, ';\n /**\n * Inline style of the element.\n * @group Props\n */\n @Input() style: { [klass: string]: any } | null | undefined;\n /**\n * Class of the element.\n * @group Props\n */\n @Input() styleClass: string | undefined;\n /**\n * Width of the image thumbnail in pixels.\n * @group Props\n */\n @Input({ transform: numberAttribute }) previewWidth: number = 50;\n /**\n * Label of the choose button. Defaults to PrimeNG Locale configuration.\n * @group Props\n */\n @Input() chooseLabel: string | undefined;\n /**\n * Label of the upload button. Defaults to PrimeNG Locale configuration.\n * @group Props\n */\n @Input() uploadLabel: string | undefined;\n /**\n * Label of the cancel button. Defaults to PrimeNG Locale configuration.\n * @group Props\n */\n @Input() cancelLabel: string | undefined;\n /**\n * Icon of the choose button.\n * @group Props\n */\n @Input() chooseIcon: string | undefined;\n /**\n * Icon of the upload button.\n * @group Props\n */\n @Input() uploadIcon: string | undefined;\n /**\n * Icon of the cancel button.\n * @group Props\n */\n @Input() cancelIcon: string | undefined;\n /**\n * Whether to show the upload button.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) showUploadButton: boolean = true;\n /**\n * Whether to show the cancel button.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) showCancelButton: boolean = true;\n /**\n * Defines the UI of the component.\n * @group Props\n */\n @Input() mode: 'advanced' | 'basic' | undefined = 'advanced';\n /**\n * HttpHeaders class represents the header configuration options for an HTTP request.\n * @group Props\n */\n @Input() headers: HttpHeaders | undefined;\n /**\n * Whether to use the default upload or a manual implementation defined in uploadHandler callback. Defaults to PrimeNG Locale configuration.\n * @group Props\n */\n @Input({ transform: booleanAttribute }) customUpload: boolean | undefined;\n /**\n * Maximum number of files that can be uploaded.\n * @group Props\n */\n @Input({ transform: (value: unknown) => numberAttribute(value, null) }) fileLimit: number | undefined;\n /**\n * Style class of the upload button.\n * @group Props\n */\n @Input() uploadStyleClass: string | undefined;\n /**\n * Style class of the cancel button.\n * @group Props\n */\n @Input() cancelStyleClass: string | undefined;\n /**\n * Style class of the remove button.\n * @group Props\n */\n @Input() removeStyleClass: string | undefined;\n /**\n * Style class of the choose button.\n * @group Props\n */\n @Input() chooseStyleClass: string | undefined;\n /**\n * Used to pass all properties of the ButtonProps to the choose button inside the component.\n * @group Props\n */\n @Input() chooseButtonProps: ButtonProps;\n /**\n * Used to pass all properties of the ButtonProps to the upload button inside the component.\n * @group Props\n */\n @Input() uploadButtonProps: ButtonProps = { severity: 'secondary' };\n /**\n * Used to pass all properties of the ButtonProps to the cancel button inside the component.\n * @group Props\n */\n @Input() cancelButtonProps: ButtonProps = { severity: 'secondary' };\n /**\n * Callback to invoke before file upload is initialized.\n * @param {FileBeforeUploadEvent} event - Custom upload event.\n * @group Emits\n */\n @Output() onBeforeUpload: EventEmitter<FileBeforeUploadEvent> = new EventEmitter<FileBeforeUploadEvent>();\n /**\n * 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.\n * @param {FileSendEvent} event - Custom send event.\n * @group Emits\n */\n @Output() onSend: EventEmitter<FileSendEvent> = new EventEmitter<FileSendEvent>();\n /**\n * Callback to invoke when file upload is complete.\n * @param {FileUploadEvent} event - Custom upload event.\n * @group Emits\n */\n @Output() onUpload: EventEmitter<FileUploadEvent> = new EventEmitter<FileUploadEvent>();\n /**\n * Callback to invoke if file upload fails.\n * @param {FileUploadErrorEvent} event - Custom error event.\n * @group Emits\n */\n @Output() onError: EventEmitter<FileUploadErrorEvent> = new EventEmitter<FileUploadErrorEvent>();\n /**\n * Callback to invoke when files in queue are removed without uploading using clear all button.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n @Output() onClear: EventEmitter<Event> = new EventEmitter<Event>();\n /**\n * Callback to invoke when a file is removed without uploading using clear button of a file.\n * @param {FileRemoveEvent} event - Remove event.\n * @group Emits\n */\n @Output() onRemove: EventEmitter<FileRemoveEvent> = new EventEmitter<FileRemoveEvent>();\n /**\n * Callback to invoke when files are selected.\n * @param {FileSelectEvent} event - Select event.\n * @group Emits\n */\n @Output() onSelect: EventEmitter<FileSelectEvent> = new EventEmitter<FileSelectEvent>();\n /**\n * Callback to invoke when files are being uploaded.\n * @param {FileProgressEvent} event - Progress event.\n * @group Emits\n */\n @Output() onProgress: EventEmitter<FileProgressEvent> = new EventEmitter<FileProgressEvent>();\n /**\n * Callback to invoke in custom upload mode to upload the files manually.\n * @param {FileUploadHandlerEvent} event - Upload handler event.\n * @group Emits\n */\n @Output() uploadHandler: EventEmitter<FileUploadHandlerEvent> = new EventEmitter<FileUploadHandlerEvent>();\n /**\n * This event is triggered if an error occurs while loading an image file.\n * @param {Event} event - Browser event.\n * @group Emits\n */\n @Output() onImageError: EventEmitter<Event> = new EventEmitter<Event>();\n /**\n * This event is triggered if an error occurs while loading an image file.\n * @param {RemoveUploadedFileEvent} event - Remove event.\n * @group Emits\n */\n @Output() onRemoveUploadedFile: EventEmitter<RemoveUploadedFileEvent> = new EventEmitter<RemoveUploadedFileEvent>();\n\n /**\n * Template for file.\n * @group Templates\n */\n @ContentChild('file', { descendants: false }) fileTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for header.\n * @group Templates\n */\n @ContentChild('header', { descendants: false }) headerTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for content.\n * @group Templates\n */\n @ContentChild('content', { descendants: false }) contentTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for toolbar.\n * @group Templates\n */\n @ContentChild('toolbar', { descendants: false }) toolbarTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for choose icon.\n * @group Templates\n */\n @ContentChild('chooseicon', { descendants: false }) chooseIconTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for file label.\n * @group Templates\n */\n @ContentChild('filelabel', { descendants: false }) fileLabelTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for upload icon.\n * @group Templates\n */\n @ContentChild('uploadicon', { descendants: false }) uploadIconTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for cancel icon.\n * @group Templates\n */\n @ContentChild('cancelicon', { descendants: false }) cancelIconTemplate: TemplateRef<any> | undefined;\n\n /**\n * Template for empty state.\n * @group Templates\n */\n @ContentChild('empty', { descendants: false }) emptyTemplate: TemplateRef<any> | undefined;\n\n @ViewChild('advancedfileinput') advancedFileInput: ElementRef | undefined | any;\n\n @ViewChild('basicfileinput') basicFileInput: ElementRef | undefined;\n\n @ViewChild('content') content: ElementRef | undefined;\n\n @Input() set files(files) {\n this._files = [];\n\n for (let i = 0; i < files.length; i++) {\n let file = files[i];\n\n if (this.validate(file)) {\n if (this.isImage(file)) {\n (<any>file).objectURL = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(files[i]));\n }\n\n this._files.push(files[i]);\n }\n }\n }\n\n get files(): File[] {\n return this._files;\n }\n\n public get basicButtonLabel(): string {\n if (this.auto || !this.hasFiles()) {\n return this.chooseLabel as string;\n }\n\n return this.uploadLabel ?? this.files[0].name;\n }\n\n public _files: File[] = [];\n\n public progress: number = 0;\n\n public dragHighlight: boolean | undefined;\n\n public msgs: any[] | undefined;\n\n public uploadedFileCount: number = 0;\n\n focus: boolean | undefined;\n\n uploading: boolean | undefined;\n\n duplicateIEEvent: boolean | undefined; // flag to recognize duplicate onchange event for file input\n\n translationSubscription: Subscription | undefined;\n\n dragOverListener: VoidListener;\n\n public uploadedFiles = [];\n\n sanitizer: DomSanitizer = inject(DomSanitizer);\n\n zone: NgZone = inject(NgZone);\n\n http: HttpClient = inject(HttpClient);\n\n _componentStyle = inject(FileUploadStyle);\n\n ngOnInit() {\n super.ngOnInit();\n this.translationSubscription = this.config.translationObserver.subscribe(() => {\n this.cd.markForCheck();\n });\n }\n\n ngAfterViewInit() {\n super.ngAfterViewInit();\n if (isPlatformBrowser(this.platformId)) {\n if (this.mode === 'advanced') {\n this.zone.runOutsideAngular(() => {\n if (this.content) {\n this.dragOverListener = this.renderer.listen(this.content.nativeElement, 'dragover', this.onDragOver.bind(this));\n }\n });\n }\n }\n }\n\n _headerTemplate: TemplateRef<any> | undefined;\n\n _contentTemplate: TemplateRef<any> | undefined;\n\n _toolbarTemplate: TemplateRef<any> | undefined;\n\n _chooseIconTemplate: TemplateRef<any> | undefined;\n\n _uploadIconTemplate: TemplateRef<any> | undefined;\n\n _cancelIconTemplate: TemplateRef<any> | undefined;\n\n _emptyTemplate: TemplateRef<any> | undefined;\n\n _fileTemplate: TemplateRef<any> | undefined;\n\n _fileLabelTemplate: TemplateRef<any> | undefined;\n\n @ContentChildren(PrimeTemplate) templates: QueryList<PrimeTemplate> | undefined;\n\n ngAfterContentInit() {\n this.templates?.forEach((item) => {\n switch (item.getType()) {\n case 'header':\n this._headerTemplate = item.template;\n break;\n\n case 'file':\n this._fileTemplate = item.template;\n break;\n\n case 'content':\n this._contentTemplate = item.template;\n break;\n\n case 'toolbar':\n this._toolbarTemplate = item.template;\n break;\n\n case 'chooseicon':\n this._chooseIconTemplate = item.template;\n break;\n\n case 'uploadicon':\n this._uploadIconTemplate = item.template;\n break;\n\n case 'cancelicon':\n this._cancelIconTemplate = item.template;\n break;\n\n case 'empty':\n this._emptyTemplate = item.template;\n break;\n\n case 'filelabel':\n this._fileLabelTemplate = item.template;\n break;\n\n default:\n this._fileTemplate = item.template;\n break;\n }\n });\n }\n\n basicFileChosenLabel() {\n if (this.auto) return this.chooseButtonLabel;\n else if (this.hasFiles()) {\n if (this.files && this.files.length === 1) return this.files[0].name;\n\n return this.config.getTranslation('fileChosenMessage')?.replace('{0}', this.files.length);\n }\n\n return this.config.getTranslation('noFileChosenMessage') || '';\n }\n\n getTranslation(option: string) {\n return this.config.getTranslation(option);\n }\n\n choose() {\n this.advancedFileInput?.nativeElement.click();\n }\n\n onFileSelect(event: any) {\n if (event.type !== 'drop' && this.isIE11() && this.duplicateIEEvent) {\n this.duplicateIEEvent = false;\n return;\n }\n\n this.msgs = [];\n if (!this.multiple) {\n this.files = [];\n }\n\n let files = event.dataTransfer ? event.dataTransfer.files : event.target.files;\n for (let i = 0; i < files.length; i++) {\n let file = files[i];\n\n if (!this.isFileSelected(file)) {\n if (this.validate(file)) {\n if (this.isImage(file)) {\n file.objectURL = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(files[i]));\n }\n\n this.files.push(files[i]);\n }\n }\n }\n\n this.onSelect.emit({ originalEvent: event, files: files, currentFiles: this.files });\n\n // this will check the fileLimit with the uploaded files\n this.checkFileLimit(files);\n\n if (this.hasFiles() && this.auto && (this.mode !== 'advanced' || !this.isFileLimitExceeded())) {\n this.upload();\n }\n\n if (event.type !== 'drop' && this.isIE11()) {\n this.clearIEInput();\n } else {\n this.clearInputElement();\n }\n }\n\n isFileSelected(file: File): boolean {\n for (let sFile of this.files) {\n if (sFile.name + sFile.type + sFile.size === file.name + file.type + file.size) {\n return true;\n }\n }\n\n return false;\n }\n\n isIE11() {\n if (isPlatformBrowser(this.platformId)) {\n return !!(this.document.defaultView as any)['MSInputMethodContext'] && !!(this.document as any)['documentMode'];\n }\n }\n\n validate(file: File): boolean {\n this.msgs = this.msgs || [];\n if (this.accept && !this.isFileTypeValid(file)) {\n const text = `${this.invalidFileTypeMessageSummary.replace('{0}', file.name)} ${this.invalidFileTypeMessageDetail.replace('{0}', this.accept)}`;\n this.msgs.push({\n severity: 'error',\n text: text\n });\n return false;\n }\n\n if (this.maxFileSize && file.size > this.maxFileSize) {\n const text = `${this.invalidFileSizeMessageSummary.replace('{0}', file.name)} ${this.invalidFileSizeMessageDetail.replace('{0}', this.formatSize(this.maxFileSize))}`;\n this.msgs.push({\n severity: 'error',\n text: text\n });\n return false;\n }\n\n return true;\n }\n\n private isFileTypeValid(file: File): boolean {\n let acceptableTypes = this.accept?.split(',').map((type) => type.trim());\n for (let type of acceptableTypes!) {\n let acceptable = this.isWildcard(type) ? this.getTypeClass(file.type) === this.getTypeClass(type) : file.type == type || this.getFileExtension(file).toLowerCase() === type.toLowerCase();\n\n if (acceptable) {\n return true;\n }\n }\n\n return false;\n }\n\n getTypeClass(fileType: string): string {\n return fileType.substring(0, fileType.indexOf('/'));\n }\n\n isWildcard(fileType: string): boolean {\n return fileType.indexOf('*') !== -1;\n }\n\n getFileExtension(file: File): string {\n return '.' + file.name.split('.').pop();\n }\n\n isImage(file: File): boolean {\n return /^image\\//.test(file.type);\n }\n\n onImageLoad(img: any) {\n window.URL.revokeObjectURL(img.src);\n }\n /**\n * Uploads the selected files.\n * @group Method\n */\n uploader() {\n if (this.customUpload) {\n if (this.fileLimit) {\n this.uploadedFileCount += this.files.length;\n }\n\n this.uploadHandler.emit({\n files: this.files\n });\n\n this.cd.markForCheck();\n } else {\n this.uploading = true;\n this.msgs = [];\n let formData = new FormData();\n\n this.onBeforeUpload.emit({\n formData: formData\n });\n\n for (let i = 0; i < this.files.length; i++) {\n formData.append(this.name!, this.files[i], this.files[i].name);\n }\n\n this.http\n .request(<string>this.method, this.url as string, {\n body: formData,\n headers: this.headers,\n reportProgress: true,\n observe: 'events',\n withCredentials: this.withCredentials\n })\n .subscribe(\n (event: HttpEvent<any>) => {\n switch (event.type) {\n case HttpEventType.Sent:\n this.onSend.emit({\n originalEvent: event,\n formData: formData\n });\n break;\n case HttpEventType.Response:\n this.uploading = false;\n this.progress = 0;\n\n if (event['status'] >= 200 && event['status'] < 300) {\n if (this.fileLimit) {\n this.uploadedFileCount += this.files.length;\n }\n\n this.onUpload.emit({ originalEvent: event, files: this.files });\n } else {\n this.onError.emit({ files: this.files });\n }\n this.uploadedFiles.push(...this.files);\n this.clear();\n break;\n case HttpEventType.UploadProgress: {\n if (event['loaded']) {\n this.progress = Math.round((event['loaded'] * 100) / event['total']!);\n }\n\n this.onProgress.emit({ originalEvent: event, progress: this.progress });\n break;\n }\n }\n\n this.cd.markForCheck();\n },\n (error: ErrorEvent) => {\n this.uploading = false;\n this.onError.emit({ files: this.files, error: error });\n }\n );\n }\n }\n /**\n * Clears the files list.\n * @group Method\n */\n clear() {\n this.files = [];\n this.uploadedFileCount = 0;\n this.onClear.emit();\n this.clearInputElement();\n this.cd.markForCheck();\n }\n /**\n * Removes a single file.\n * @param {Event} event - Browser event.\n * @param {Number} index - Index of the file.\n * @group Method\n */\n remove(event: Event, index: number) {\n this.clearInputElement();\n this.onRemove.emit({ originalEvent: event, file: this.files[index] });\n this.files.splice(index, 1);\n this.checkFileLimit(this.files);\n }\n /**\n * Removes uploaded file.\n * @param {Number} index - Index of the file to be removed.\n * @group Method\n */\n removeUploadedFile(index) {\n let removedFile = this.uploadedFiles.splice(index, 1)[0];\n this.uploadedFiles = [...this.uploadedFiles];\n this.onRemoveUploadedFile.emit({ file: removedFile, files: this.uploadedFiles });\n }\n\n isFileLimitExceeded() {\n const isAutoMode = this.auto;\n const totalFileCount = isAutoMode ? this.files.length : this.files.length + this.uploadedFileCount;\n\n if (this.fileLimit && this.fileLimit <= totalFileCount && this.focus) {\n this.focus = false;\n }\n\n return this.fileLimit && this.fileLimit < totalFileCount;\n }\n\n isChooseDisabled() {\n if (this.auto) {\n return this.fileLimit && this.fileLimit <= this.files.length;\n } else {\n return this.fileLimit && this.fileLimit <= this.files.length + this.uploadedFileCount;\n }\n }\n\n checkFileLimit(files: File[]) {\n this.msgs = [];\n const hasExistingValidationMessages = this.msgs.length > 0 && this.fileLimit && this.fileLimit < files.length;\n if (this.isFileLimitExceeded() || hasExistingValidationMessages) {\n const text = `${this.invalidFileLimitMessageSummary.replace('{0}', (this.fileLimit as number).toString())} ${this.invalidFileLimitMessageDetail.replace('{0}', (this.fileLimit as number).toString())}`;\n this.msgs.push({\n severity: 'error',\n text: text\n });\n }\n }\n\n clearInputElement() {\n if (this.advancedFileInput && this.advancedFileInput.nativeElement) {\n this.advancedFileInput.nativeElement.value = '';\n }\n\n if (this.basicFileInput && this.basicFileInput.nativeElement) {\n this.basicFileInput.nativeElement.value = '';\n }\n }\n\n clearIEInput() {\n if (this.advancedFileInput && this.advancedFileInput.nativeElement) {\n this.duplicateIEEvent = true; //IE11 fix to prevent onFileChange trigger again\n this.advancedFileInput.nativeElement.value = '';\n }\n }\n\n hasFiles(): boolean {\n return this.files && this.files.length > 0;\n }\n\n hasUploadedFiles() {\n return this.uploadedFiles && this.uploadedFiles.length > 0;\n }\n\n onDragEnter(e: DragEvent) {\n if (!this.disabled) {\n e.stopPropagation();\n e.preventDefault();\n }\n }\n\n onDragOver(e: DragEvent) {\n if (!this.disabled) {\n addClass(this.content?.nativeElement, 'p-fileupload-highlight');\n this.dragHighlight = true;\n e.stopPropagation();\n e.preventDefault();\n }\n }\n\n onDragLeave(event: DragEvent) {\n if (!this.disabled) {\n removeClass(this.content?.nativeElement, 'p-fileupload-highlight');\n }\n }\n\n onDrop(event: any) {\n if (!this.disabled) {\n removeClass(this.content?.nativeElement, 'p-fileupload-highlight');\n event.stopPropagation();\n event.preventDefault();\n\n let files = event.dataTransfer ? event.dataTransfer.files : event.target.files;\n let allowDrop = this.multiple || (files && files.length === 1);\n\n if (allowDrop) {\n this.onFileSelect(event);\n }\n }\n }\n\n onFocus() {\n this.focus = true;\n }\n\n onBlur() {\n this.focus = false;\n }\n\n formatSize(bytes: number) {\n const k = 1024;\n const dm = 3;\n const sizes = this.getTranslation(TranslationKeys.FILE_SIZE_TYPES);\n\n if (bytes === 0) {\n return `0 ${sizes[0]}`;\n }\n\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const formattedSize = (bytes / Math.pow(k, i)).toFixed(dm);\n\n return `${formattedSize} ${sizes[i]}`;\n }\n\n upload() {\n if (this.hasFiles()) this.uploader();\n }\n\n onBasicUploaderClick() {\n this.basicFileInput?.nativeElement.click();\n }\n\n onBasicKeydown(event: KeyboardEvent) {\n switch (event.code) {\n case 'Space':\n case 'Enter':\n this.onBasicUploaderClick();\n\n event.preventDefault();\n break;\n }\n }\n\n imageError(event: Event) {\n this.onImageError.emit(event);\n }\n\n getBlockableElement(): HTMLElement {\n return this.el.nativeElement.children[0];\n }\n\n get chooseButtonLabel(): string {\n return this.chooseLabel || this.config.getTranslation(TranslationKeys.CHOOSE);\n }\n\n get uploadButtonLabel(): string {\n return this.uploadLabel || this.config.getTranslation(TranslationKeys.UPLOAD);\n }\n\n get cancelButtonLabel(): string {\n return this.cancelLabel || this.config.getTranslation(TranslationKeys.CANCEL);\n }\n\n get browseFilesLabel(): string {\n return this.config.getTranslation(TranslationKeys.ARIA)[TranslationKeys.BROWSE_FILES];\n }\n\n get pendingLabel() {\n return this.config.getTranslation(TranslationKeys.PENDING);\n }\n\n ngOnDestroy() {\n if (this.content && this.content.nativeElement) {\n if (this.dragOverListener) {\n this.dragOverListener();\n this.dragOverListener = null;\n }\n }\n\n if (this.translationSubscription) {\n this.translationSubscription.unsubscribe();\n }\n\n super.ngOnDestroy();\n }\n}\n\n@NgModule({\n imports: [FileUpload, SharedModule],\n exports: [FileUpload, SharedModule]\n})\nexport class FileUploadModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAGA,MAAM,KAAK,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK;;;;;;wBAMF,EAAE,CAAC,yBAAyB,CAAC,CAAA;qBAChC,EAAE,CAAC,0BAA0B,CAAC,CAAA;kBACjC,EAAE,CAAC,uBAAuB,CAAC,CAAA;aAChC,EAAE,CAAC,kBAAkB,CAAC,CAAA;;;;;;eAMpB,EAAE,CAAC,2BAA2B,CAAC,CAAA;kBAC5B,EAAE,CAAC,8BAA8B,CAAC,CAAA;aACvC,EAAE,CAAC,yBAAyB,CAAC,CAAA;;oBAEtB,EAAE,CAAC,gCAAgC,CAAC,CAAA;oBACpC,EAAE,CAAC,gCAAgC,CAAC,CAAA;qBACnC,EAAE,CAAC,iCAAiC,CAAC,CAAA;WAC/C,EAAE,CAAC,uBAAuB,CAAC,CAAA;;;;;;;WAO3B,EAAE,CAAC,wBAAwB,CAAC,CAAA;+BACR,EAAE,CAAC,gCAAgC,CAAC,CAAA;eACpD,EAAE,CAAC,4BAA4B,CAAC,CAAA;;;;;cAKjC,EAAE,CAAC,+BAA+B,CAAC,CAAA;;;;;;WAMtC,EAAE,CAAC,yBAAyB,CAAC,CAAA;;;;;;;eAOzB,EAAE,CAAC,yBAAyB,CAAC,CAAA;+BACb,EAAE,CAAC,8BAA8B,CAAC,CAAA;WACtD,EAAE,CAAC,qBAAqB,CAAC,CAAA;;;;;;;;;;WAUzB,EAAE,CAAC,0BAA0B,CAAC,CAAA;;;;;;;;;;;;yBAYhB,EAAE,CAAC,2CAA2C,CAAC,CAAA;;;;;;;;;;;;WAY7D,EAAE,CAAC,sBAAsB,CAAC,CAAA;;CAEpC;AAED,MAAM,OAAO,GAAG;AACZ,IAAA,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,CAA6B,0BAAA,EAAA,QAAQ,CAAC,IAAI,CAAc,YAAA,CAAA;AAChF,IAAA,MAAM,EAAE,qBAAqB;AAC7B,IAAA,cAAc,EAAE,4BAA4B;AAC5C,IAAA,cAAc,EAAE,4BAA4B;AAC5C,IAAA,cAAc,EAAE,4BAA4B;AAC5C,IAAA,OAAO,EAAE,sBAAsB;AAC/B,IAAA,QAAQ,EAAE,wBAAwB;AAClC,IAAA,IAAI,EAAE,mBAAmB;AACzB,IAAA,aAAa,EAAE,6BAA6B;AAC5C,IAAA,QAAQ,EAAE,wBAAwB;AAClC,IAAA,QAAQ,EAAE,wBAAwB;AAClC,IAAA,QAAQ,EAAE,wBAAwB;AAClC,IAAA,WAAW,EAAE,yBAAyB;AACtC,IAAA,WAAW,EAAE,2BAA2B;AACxC,IAAA,kBAAkB,EAAE;CACvB;AAGK,MAAO,eAAgB,SAAQ,SAAS,CAAA;IAC1C,IAAI,GAAG,YAAY;IAEnB,KAAK,GAAG,KAAK;IAEb,OAAO,GAAG,OAAO;uGALR,eAAe,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAf,eAAe,EAAA,CAAA;;2FAAf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B;;AASD;;;;;;;;AAQG;IAES;AAAZ,CAAA,UAAY,iBAAiB,EAAA;AACz