UNPKG

primeng

Version:

[![npm version](https://badge.fury.io/js/primeng.svg)](https://badge.fury.io/js/primeng) [![npm downloads](https://img.shields.io/npm/dm/primeng.svg)](https://www.npmjs.com/package/primeng) [![Actions CI](https://github.com/primefaces/primeng/workflows/No

1,044 lines (1,036 loc) 56.5 kB
import * as i4 from '@angular/common'; import { isPlatformBrowser, DOCUMENT, CommonModule } from '@angular/common'; import * as i2 from '@angular/common/http'; import { HttpEventType } from '@angular/common/http'; import * as i0 from '@angular/core'; import { EventEmitter, PLATFORM_ID, booleanAttribute, numberAttribute, Component, ChangeDetectionStrategy, ViewEncapsulation, Inject, Input, Output, ContentChildren, ViewChild, NgModule } from '@angular/core'; import * as i3 from 'primeng/api'; import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api'; import * as i5 from 'primeng/button'; import { ButtonModule } from 'primeng/button'; import { DomHandler } from 'primeng/dom'; import { PlusIcon } from 'primeng/icons/plus'; import { TimesIcon } from 'primeng/icons/times'; import { UploadIcon } from 'primeng/icons/upload'; import * as i7 from 'primeng/messages'; import { MessagesModule } from 'primeng/messages'; import * as i6 from 'primeng/progressbar'; import { ProgressBarModule } from 'primeng/progressbar'; import * as i8 from 'primeng/ripple'; import { RippleModule } from 'primeng/ripple'; import * as i1 from '@angular/platform-browser'; /** * FileUpload is an advanced uploader with dragdrop support, multi file uploads, auto uploading, progress tracking and validations. * @group Components */ class FileUpload { document; platformId; renderer; el; sanitizer; zone; http; cd; config; /** * 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; /** * 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(); templates; 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; fileTemplate; headerTemplate; contentTemplate; toolbarTemplate; chooseIconTemplate; uploadIconTemplate; cancelIconTemplate; emptyTemplate; uploadedFileCount = 0; focus; uploading; duplicateIEEvent; // flag to recognize duplicate onchange event for file input translationSubscription; dragOverListener; uploadedFiles = []; constructor(document, platformId, renderer, el, sanitizer, zone, http, cd, config) { this.document = document; this.platformId = platformId; this.renderer = renderer; this.el = el; this.sanitizer = sanitizer; this.zone = zone; this.http = http; this.cd = cd; this.config = config; } 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; default: this.fileTemplate = item.template; break; } }); } ngOnInit() { this.translationSubscription = this.config.translationObserver.subscribe(() => { this.cd.markForCheck(); }); } 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)); } }); } } } 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)) { this.msgs.push({ severity: 'error', summary: this.invalidFileTypeMessageSummary.replace('{0}', file.name), detail: this.invalidFileTypeMessageDetail.replace('{0}', this.accept) }); return false; } if (this.maxFileSize && file.size > this.maxFileSize) { this.msgs.push({ severity: 'error', summary: this.invalidFileSizeMessageSummary.replace('{0}', file.name), detail: this.invalidFileSizeMessageDetail.replace('{0}', this.formatSize(this.maxFileSize)) }); 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 */ upload() { 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.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 < files.length; if (this.isFileLimitExceeded() || hasExistingValidationMessages) { this.msgs.push({ severity: 'error', summary: this.invalidFileLimitMessageSummary.replace('{0}', this.fileLimit.toString()), detail: this.invalidFileLimitMessageDetail.replace('{0}', this.fileLimit.toString()) }); } } 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) { DomHandler.addClass(this.content?.nativeElement, 'p-fileupload-highlight'); this.dragHighlight = true; e.stopPropagation(); e.preventDefault(); } } onDragLeave(event) { if (!this.disabled) { DomHandler.removeClass(this.content?.nativeElement, 'p-fileupload-highlight'); } } onDrop(event) { if (!this.disabled) { DomHandler.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]}`; } onBasicUploaderClick() { if (this.hasFiles()) this.upload(); else 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]; } ngOnDestroy() { if (this.content && this.content.nativeElement) { if (this.dragOverListener) { this.dragOverListener(); this.dragOverListener = null; } } if (this.translationSubscription) { this.translationSubscription.unsubscribe(); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FileUpload, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i1.DomSanitizer }, { token: i0.NgZone }, { token: i2.HttpClient }, { token: i0.ChangeDetectorRef }, { token: i3.PrimeNGConfig }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "18.0.1", type: FileUpload, selector: "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", 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" }, host: { classAttribute: "p-element" }, queries: [{ 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 }], 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-buttonbar" [attr.data-pc-section]="'buttonbar'"> <ng-container *ngIf="!headerTemplate"> <span class="p-button p-component p-fileupload-choose" [ngClass]="{ 'p-focus': focus, 'p-disabled': disabled || isChooseDisabled() }" (focus)="onFocus()" (blur)="onBlur()" pRipple (click)="choose()" (keydown.enter)="choose()" tabindex="0" [class]="chooseStyleClass" [attr.data-pc-section]="'choosebutton'" > <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" [ngClass]="'p-button-icon p-button-icon-left'" [class]="chooseIcon" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon *ngIf="!chooseIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'" /> <span *ngIf="chooseIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"> <ng-template *ngTemplateOutlet="chooseIconTemplate"></ng-template> </span> </ng-container> <span class="p-button-label" [attr.data-pc-section]="'choosebuttonlabel'">{{ chooseButtonLabel }}</span> </span> <p-button *ngIf="!auto && showUploadButton" type="button" [label]="uploadButtonLabel" (onClick)="upload()" [disabled]="!hasFiles() || isFileLimitExceeded()" [styleClass]="uploadStyleClass"> <span *ngIf="uploadIcon" [ngClass]="uploadIcon" [attr.aria-hidden]="true" class="p-button-icon p-button-icon-left"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" /> <span *ngIf="uploadIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="uploadIconTemplate"></ng-template> </span> </ng-container> </p-button> <p-button *ngIf="!auto && showCancelButton" type="button" [label]="cancelButtonLabel" (onClick)="clear()" [disabled]="!hasFiles() || uploading" [styleClass]="cancelStyleClass"> <span *ngIf="cancelIcon" [ngClass]="cancelIcon" class="p-button-icon p-button-icon-left"></span> <ng-container *ngIf="!cancelIcon"> <TimesIcon *ngIf="!cancelIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" [attr.aria-hidden]="true" /> <span *ngIf="cancelIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="cancelIconTemplate"></ng-template> </span> </ng-container> </p-button> </ng-container> <ng-container *ngTemplateOutlet="headerTemplate; context: { $implicit: files, uploadedFiles: uploadedFiles, chooseCallback: choose.bind(this), clearCallback: clear.bind(this), uploadCallback: upload.bind(this) }"></ng-container> <ng-container *ngTemplateOutlet="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> <p-messages [value]="msgs" [enableService]="false"></p-messages> <div class="p-fileupload-files" *ngIf="hasFiles()"> <div *ngIf="!fileTemplate"> <div class="p-fileupload-row" *ngFor="let file of files; let i = index"> <div *ngIf="isImage(file)"><img [src]="file.objectURL" [width]="previewWidth" (error)="imageError($event)" /></div> <div class="p-fileupload-filename">{{ file.name }}</div> <div>{{ formatSize(file.size) }}</div> <div> <button type="button" pButton (click)="remove($event, i)" [disabled]="uploading" class="p-button-icon-only" [class]="removeStyleClass"> <TimesIcon *ngIf="!cancelIconTemplate" /> <ng-template *ngTemplateOutlet="cancelIconTemplate"></ng-template> </button> </div> </div> </div> <div *ngIf="fileTemplate"> <ng-template ngFor [ngForOf]="files" [ngForTemplate]="fileTemplate"></ng-template> </div> </div> <ng-container *ngTemplateOutlet=" 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> <div *ngIf="emptyTemplate && !hasFiles() && !hasUploadedFiles()" class="p-fileupload-empty"> <ng-container *ngTemplateOutlet="emptyTemplate"></ng-container> </div> </div> </div> <div class="p-fileupload p-fileupload-basic p-component" *ngIf="mode === 'basic'" [attr.data-pc-name]="'fileupload'"> <p-messages [value]="msgs" [enableService]="false"></p-messages> <span [ngClass]="{ 'p-button p-component p-fileupload-choose': true, 'p-button-icon-only': !basicButtonLabel, 'p-fileupload-choose-selected': hasFiles(), 'p-focus': focus, 'p-disabled': disabled }" [ngStyle]="style" [class]="styleClass" (click)="onBasicUploaderClick()" (keydown)="onBasicKeydown($event)" tabindex="0" pRipple [attr.data-pc-section]="'choosebutton'" > <ng-container *ngIf="hasFiles() && !auto; else chooseSection"> <span *ngIf="uploadIcon" class="p-button-icon p-button-icon-left" [ngClass]="uploadIcon"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" /> <span *ngIf="uploadIconTemplate" class="p-button-icon p-button-icon-left"> <ng-template *ngTemplateOutlet="uploadIconTemplate"></ng-template> </span> </ng-container> </ng-container> <ng-template #chooseSection> <span *ngIf="chooseIcon" class="p-button-icon p-button-icon-left pi" [ngClass]="chooseIcon"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon [styleClass]="'p-button-icon p-button-icon-left pi'" *ngIf="!chooseIconTemplate" [attr.aria-hidden]="true" [attr.data-pc-section]="'uploadicon'" /> <span *ngIf="chooseIconTemplate" class="p-button-icon p-button-icon-left pi" [attr.aria-hidden]="true" [attr.data-pc-section]="'uploadicon'"> <ng-template *ngTemplateOutlet="chooseIconTemplate"></ng-template> </span> </ng-container> </ng-template> <span *ngIf="basicButtonLabel" class="p-button-label" [attr.data-pc-section]="'label'">{{ basicButtonLabel }}</span> <input [attr.aria-label]="browseFilesLabel" #basicfileinput type="file" [accept]="accept" [multiple]="multiple" [disabled]="disabled" (change)="onFileSelect($event)" *ngIf="!hasFiles()" (focus)="onFocus()" (blur)="onBlur()" [attr.data-pc-section]="'input'" /> </span> </div> `, isInline: true, styles: ["@layer primeng{.p-fileupload-content{position:relative}.p-fileupload-row{display:flex;align-items:center}.p-fileupload-row>div{flex:1 1 auto;width:25%}.p-fileupload-row>div:last-child{text-align:right}.p-fileupload-content .p-progressbar{width:100%;position:absolute;top:0;left:0}.p-button.p-fileupload-choose{position:relative;overflow:hidden}.p-button.p-fileupload-choose input[type=file],.p-fileupload-choose.p-fileupload-choose-selected input[type=file]{display:none}.p-fluid .p-fileupload .p-button{width:auto}.p-fileupload-filename{word-break:break-all}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(() => i4.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i4.NgForOf), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i4.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i4.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => i4.NgStyle), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i0.forwardRef(() => i5.ButtonDirective), selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain"] }, { kind: "component", type: i0.forwardRef(() => i5.Button), selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "style", "styleClass", "badgeClass", "ariaLabel", "autofocus"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i0.forwardRef(() => i6.ProgressBar), selector: "p-progressBar", inputs: ["value", "showValue", "styleClass", "style", "unit", "mode", "color"] }, { kind: "component", type: i0.forwardRef(() => i7.Messages), selector: "p-messages", inputs: ["value", "closable", "style", "styleClass", "enableService", "key", "escape", "severity", "showTransitionOptions", "hideTransitionOptions"], outputs: ["valueChange", "onClose"] }, { kind: "directive", type: i0.forwardRef(() => i8.Ripple), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(() => PlusIcon), selector: "PlusIcon" }, { kind: "component", type: i0.forwardRef(() => UploadIcon), selector: "UploadIcon" }, { kind: "component", type: i0.forwardRef(() => TimesIcon), selector: "TimesIcon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FileUpload, decorators: [{ type: Component, args: [{ selector: 'p-fileUpload', 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-buttonbar" [attr.data-pc-section]="'buttonbar'"> <ng-container *ngIf="!headerTemplate"> <span class="p-button p-component p-fileupload-choose" [ngClass]="{ 'p-focus': focus, 'p-disabled': disabled || isChooseDisabled() }" (focus)="onFocus()" (blur)="onBlur()" pRipple (click)="choose()" (keydown.enter)="choose()" tabindex="0" [class]="chooseStyleClass" [attr.data-pc-section]="'choosebutton'" > <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" [ngClass]="'p-button-icon p-button-icon-left'" [class]="chooseIcon" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon *ngIf="!chooseIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'" /> <span *ngIf="chooseIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-label]="true" [attr.data-pc-section]="'chooseicon'"> <ng-template *ngTemplateOutlet="chooseIconTemplate"></ng-template> </span> </ng-container> <span class="p-button-label" [attr.data-pc-section]="'choosebuttonlabel'">{{ chooseButtonLabel }}</span> </span> <p-button *ngIf="!auto && showUploadButton" type="button" [label]="uploadButtonLabel" (onClick)="upload()" [disabled]="!hasFiles() || isFileLimitExceeded()" [styleClass]="uploadStyleClass"> <span *ngIf="uploadIcon" [ngClass]="uploadIcon" [attr.aria-hidden]="true" class="p-button-icon p-button-icon-left"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" /> <span *ngIf="uploadIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="uploadIconTemplate"></ng-template> </span> </ng-container> </p-button> <p-button *ngIf="!auto && showCancelButton" type="button" [label]="cancelButtonLabel" (onClick)="clear()" [disabled]="!hasFiles() || uploading" [styleClass]="cancelStyleClass"> <span *ngIf="cancelIcon" [ngClass]="cancelIcon" class="p-button-icon p-button-icon-left"></span> <ng-container *ngIf="!cancelIcon"> <TimesIcon *ngIf="!cancelIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" [attr.aria-hidden]="true" /> <span *ngIf="cancelIconTemplate" class="p-button-icon p-button-icon-left" [attr.aria-hidden]="true"> <ng-template *ngTemplateOutlet="cancelIconTemplate"></ng-template> </span> </ng-container> </p-button> </ng-container> <ng-container *ngTemplateOutlet="headerTemplate; context: { $implicit: files, uploadedFiles: uploadedFiles, chooseCallback: choose.bind(this), clearCallback: clear.bind(this), uploadCallback: upload.bind(this) }"></ng-container> <ng-container *ngTemplateOutlet="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> <p-messages [value]="msgs" [enableService]="false"></p-messages> <div class="p-fileupload-files" *ngIf="hasFiles()"> <div *ngIf="!fileTemplate"> <div class="p-fileupload-row" *ngFor="let file of files; let i = index"> <div *ngIf="isImage(file)"><img [src]="file.objectURL" [width]="previewWidth" (error)="imageError($event)" /></div> <div class="p-fileupload-filename">{{ file.name }}</div> <div>{{ formatSize(file.size) }}</div> <div> <button type="button" pButton (click)="remove($event, i)" [disabled]="uploading" class="p-button-icon-only" [class]="removeStyleClass"> <TimesIcon *ngIf="!cancelIconTemplate" /> <ng-template *ngTemplateOutlet="cancelIconTemplate"></ng-template> </button> </div> </div> </div> <div *ngIf="fileTemplate"> <ng-template ngFor [ngForOf]="files" [ngForTemplate]="fileTemplate"></ng-template> </div> </div> <ng-container *ngTemplateOutlet=" 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> <div *ngIf="emptyTemplate && !hasFiles() && !hasUploadedFiles()" class="p-fileupload-empty"> <ng-container *ngTemplateOutlet="emptyTemplate"></ng-container> </div> </div> </div> <div class="p-fileupload p-fileupload-basic p-component" *ngIf="mode === 'basic'" [attr.data-pc-name]="'fileupload'"> <p-messages [value]="msgs" [enableService]="false"></p-messages> <span [ngClass]="{ 'p-button p-component p-fileupload-choose': true, 'p-button-icon-only': !basicButtonLabel, 'p-fileupload-choose-selected': hasFiles(), 'p-focus': focus, 'p-disabled': disabled }" [ngStyle]="style" [class]="styleClass" (click)="onBasicUploaderClick()" (keydown)="onBasicKeydown($event)" tabindex="0" pRipple [attr.data-pc-section]="'choosebutton'" > <ng-container *ngIf="hasFiles() && !auto; else chooseSection"> <span *ngIf="uploadIcon" class="p-button-icon p-button-icon-left" [ngClass]="uploadIcon"></span> <ng-container *ngIf="!uploadIcon"> <UploadIcon *ngIf="!uploadIconTemplate" [styleClass]="'p-button-icon p-button-icon-left'" /> <span *ngIf="uploadIconTemplate" class="p-button-icon p-button-icon-left"> <ng-template *ngTemplateOutlet="uploadIconTemplate"></ng-template> </span> </ng-container> </ng-container> <ng-template #chooseSection> <span *ngIf="chooseIcon" class="p-button-icon p-button-icon-left pi" [ngClass]="chooseIcon"></span> <ng-container *ngIf="!chooseIcon"> <PlusIcon [styleClass]="'p-button-icon p-button-icon-left pi'" *ngIf="!chooseIconTemplate" [attr.aria-hidden]="true" [attr.data-pc-section]="'uploadicon'" /> <span *ngIf="chooseIconTemplate" class="p-button-icon p-button-icon-left pi" [attr.aria-hidden]="true" [attr.data-pc-section]="'uploadicon'"> <ng-template *ngTemplateOutlet="chooseIconTemplate"></ng-template> </span> </ng-container> </ng-template> <span *ngIf="basicButtonLabel" class="p-button-label" [attr.data-pc-section]="'label'">{{ basicButtonLabel }}</span> <input [attr.aria-label]="browseFilesLabel" #basicfileinput type="file" [accept]="accept" [multiple]="multiple" [disabled]="disabled" (change)="onFileSelect($event)" *ngIf="!hasFiles()" (focus)="onFocus()" (blur)="onBlur()" [attr.data-pc-section]="'input'" /> </span> </div> `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'p-element'