UNPKG

ngx-mat-file-input

Version:

This is a fork of the file input management for Angular Material initially maintained on https://merlosy.github.io/ngx-material-file-input/

455 lines (445 loc) 17.3 kB
import { InjectionToken, ElementRef, Renderer2, Optional, Self, Input, HostBinding, HostListener, Component, Inject, Pipe, NgModule } from '@angular/core'; import { __extends, __decorate, __metadata, __param } from 'tslib'; import { FocusMonitor } from '@angular/cdk/a11y'; import { NgControl, NgForm, FormGroupDirective } from '@angular/forms'; import { mixinErrorState, ErrorStateMatcher } from '@angular/material/core'; import { MatFormFieldControl } from '@angular/material/form-field'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; /** * Optional token to provide custom configuration to the module */ var NGX_MAT_FILE_INPUT_CONFIG = new InjectionToken('ngx-mat-file-input.config'); /** * Provide additional configuration to dynamically customize the module injection */ var FileInputConfig = /** @class */ (function () { function FileInputConfig() { } return FileInputConfig; }()); /** * The files to be uploaded */ var FileInput = /** @class */ (function () { function FileInput(_files, delimiter) { if (delimiter === void 0) { delimiter = ', '; } this._files = _files; this.delimiter = delimiter; this._fileNames = (this._files || []).map(function (f) { return f.name; }).join(delimiter); } Object.defineProperty(FileInput.prototype, "files", { get: function () { return this._files || []; }, enumerable: true, configurable: true }); Object.defineProperty(FileInput.prototype, "fileNames", { get: function () { return this._fileNames; }, enumerable: true, configurable: true }); return FileInput; }()); // Boilerplate for applying mixins to FileInput /** @docs-private */ var FileInputBase = /** @class */ (function () { function FileInputBase(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) { this._defaultErrorStateMatcher = _defaultErrorStateMatcher; this._parentForm = _parentForm; this._parentFormGroup = _parentFormGroup; this.ngControl = ngControl; } return FileInputBase; }()); /** * Allows to use a custom ErrorStateMatcher with the file-input component */ var FileInputMixinBase = mixinErrorState(FileInputBase); var FileInputComponent = /** @class */ (function (_super) { __extends(FileInputComponent, _super); /** * @see https://angular.io/api/forms/ControlValueAccessor */ function FileInputComponent(fm, _elementRef, _renderer, _defaultErrorStateMatcher, ngControl, _parentForm, _parentFormGroup) { var _this = _super.call(this, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) || this; _this.fm = fm; _this._elementRef = _elementRef; _this._renderer = _renderer; _this._defaultErrorStateMatcher = _defaultErrorStateMatcher; _this.ngControl = ngControl; _this._parentForm = _parentForm; _this._parentFormGroup = _parentFormGroup; _this.focused = false; _this.controlType = 'file-input'; _this.autofilled = false; _this._required = false; _this.accept = null; _this.id = "ngx-mat-file-input-" + FileInputComponent_1.nextId++; _this.describedBy = ''; _this._onChange = function (_) { }; _this._onTouched = function () { }; if (_this.ngControl != null) { _this.ngControl.valueAccessor = _this; } fm.monitor(_elementRef.nativeElement, true).subscribe(function (origin) { _this.focused = !!origin; _this.stateChanges.next(); }); return _this; } FileInputComponent_1 = FileInputComponent; FileInputComponent.prototype.setDescribedByIds = function (ids) { this.describedBy = ids.join(' '); }; Object.defineProperty(FileInputComponent.prototype, "value", { get: function () { return this.empty ? null : new FileInput(this._elementRef.nativeElement.value || []); }, set: function (fileInput) { if (fileInput) { this.writeValue(fileInput); this.stateChanges.next(); } }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "placeholder", { get: function () { return this._placeholder; }, set: function (plh) { this._placeholder = plh; this.stateChanges.next(); }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "empty", { /** * Whether the current input has files */ get: function () { return !this._elementRef.nativeElement.value || this._elementRef.nativeElement.value.length === 0; }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "shouldLabelFloat", { get: function () { return this.focused || !this.empty || this.valuePlaceholder !== undefined; }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "required", { get: function () { return this._required; }, set: function (req) { this._required = coerceBooleanProperty(req); this.stateChanges.next(); }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "isDisabled", { get: function () { return this.disabled; }, enumerable: true, configurable: true }); Object.defineProperty(FileInputComponent.prototype, "disabled", { get: function () { return this._elementRef.nativeElement.disabled; }, set: function (dis) { this.setDisabledState(coerceBooleanProperty(dis)); this.stateChanges.next(); }, enumerable: true, configurable: true }); FileInputComponent.prototype.onContainerClick = function (event) { if (event.target.tagName.toLowerCase() !== 'input' && !this.disabled) { this._elementRef.nativeElement.querySelector('input').focus(); this.focused = true; this.open(); } }; Object.defineProperty(FileInputComponent.prototype, "fileNames", { get: function () { return this.value ? this.value.fileNames : this.valuePlaceholder; }, enumerable: true, configurable: true }); FileInputComponent.prototype.writeValue = function (obj) { this._renderer.setProperty(this._elementRef.nativeElement, 'value', obj instanceof FileInput ? obj.files : null); }; FileInputComponent.prototype.registerOnChange = function (fn) { this._onChange = fn; }; FileInputComponent.prototype.registerOnTouched = function (fn) { this._onTouched = fn; }; /** * Remove all files from the file input component * @param [event] optional event that may have triggered the clear action */ FileInputComponent.prototype.clear = function (event) { if (event) { event.preventDefault(); event.stopPropagation(); } this.value = new FileInput([]); this._elementRef.nativeElement.querySelector('input').value = null; this._onChange(this.value); }; FileInputComponent.prototype.change = function (event) { var fileList = event.target.files; var fileArray = []; if (fileList) { for (var i = 0; i < fileList.length; i++) { fileArray.push(fileList[i]); } } this.value = new FileInput(fileArray); this._onChange(this.value); }; FileInputComponent.prototype.blur = function () { this.focused = false; this._onTouched(); }; FileInputComponent.prototype.setDisabledState = function (isDisabled) { this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled); }; FileInputComponent.prototype.ngOnInit = function () { this.multiple = coerceBooleanProperty(this.multiple); }; FileInputComponent.prototype.open = function () { if (!this.disabled) { this._elementRef.nativeElement.querySelector('input').click(); } }; FileInputComponent.prototype.ngOnDestroy = function () { this.stateChanges.complete(); this.fm.stopMonitoring(this._elementRef.nativeElement); }; FileInputComponent.prototype.ngDoCheck = function () { if (this.ngControl) { // We need to re-evaluate this on every change detection cycle, because there are some // error triggers that we can't subscribe to (e.g. parent form submissions). This means // that whatever logic is in here has to be super lean or we risk destroying the performance. this.updateErrorState(); } }; var FileInputComponent_1; FileInputComponent.nextId = 0; FileInputComponent.ctorParameters = function () { return [ { type: FocusMonitor }, { type: ElementRef }, { type: Renderer2 }, { type: ErrorStateMatcher }, { type: NgControl, decorators: [{ type: Optional }, { type: Self }] }, { type: NgForm, decorators: [{ type: Optional }] }, { type: FormGroupDirective, decorators: [{ type: Optional }] } ]; }; __decorate([ Input(), __metadata("design:type", Object) ], FileInputComponent.prototype, "autofilled", void 0); __decorate([ Input(), __metadata("design:type", String) ], FileInputComponent.prototype, "valuePlaceholder", void 0); __decorate([ Input(), __metadata("design:type", Boolean) ], FileInputComponent.prototype, "multiple", void 0); __decorate([ Input(), __metadata("design:type", Object) ], FileInputComponent.prototype, "accept", void 0); __decorate([ Input(), __metadata("design:type", ErrorStateMatcher) ], FileInputComponent.prototype, "errorStateMatcher", void 0); __decorate([ HostBinding(), __metadata("design:type", Object) ], FileInputComponent.prototype, "id", void 0); __decorate([ HostBinding('attr.aria-describedby'), __metadata("design:type", Object) ], FileInputComponent.prototype, "describedBy", void 0); __decorate([ Input(), __metadata("design:type", Object), __metadata("design:paramtypes", [Object]) ], FileInputComponent.prototype, "value", null); __decorate([ Input(), __metadata("design:type", Object), __metadata("design:paramtypes", [Object]) ], FileInputComponent.prototype, "placeholder", null); __decorate([ HostBinding('class.mat-form-field-should-float'), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], FileInputComponent.prototype, "shouldLabelFloat", null); __decorate([ Input(), __metadata("design:type", Boolean), __metadata("design:paramtypes", [Boolean]) ], FileInputComponent.prototype, "required", null); __decorate([ HostBinding('class.file-input-disabled'), __metadata("design:type", Object), __metadata("design:paramtypes", []) ], FileInputComponent.prototype, "isDisabled", null); __decorate([ Input(), __metadata("design:type", Boolean), __metadata("design:paramtypes", [Boolean]) ], FileInputComponent.prototype, "disabled", null); __decorate([ HostListener('change', ['$event']), __metadata("design:type", Function), __metadata("design:paramtypes", [Event]), __metadata("design:returntype", void 0) ], FileInputComponent.prototype, "change", null); __decorate([ HostListener('focusout'), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], FileInputComponent.prototype, "blur", null); FileInputComponent = FileInputComponent_1 = __decorate([ Component({ // tslint:disable-next-line:component-selector selector: 'ngx-mat-file-input', template: "<input #input type=\"file\" [attr.multiple]=\"multiple? '' : null\" [attr.accept]=\"accept\">\n<span class=\"filename\" [title]=\"fileNames\">{{ fileNames }}</span>\n", providers: [{ provide: MatFormFieldControl, useExisting: FileInputComponent_1 }], styles: [":host{display:inline-block;width:100%}:host:not(.file-input-disabled){cursor:pointer}input{width:0;height:0;opacity:0;overflow:hidden;position:absolute;z-index:-1}.filename{display:inline-block;text-overflow:ellipsis;overflow:hidden;width:100%}"] }), __param(4, Optional()), __param(4, Self()), __param(5, Optional()), __param(6, Optional()), __metadata("design:paramtypes", [FocusMonitor, ElementRef, Renderer2, ErrorStateMatcher, NgControl, NgForm, FormGroupDirective]) ], FileInputComponent); return FileInputComponent; }(FileInputMixinBase)); var ByteFormatPipe = /** @class */ (function () { function ByteFormatPipe(config) { this.config = config; this.unit = config ? config.sizeUnit : 'Byte'; } ByteFormatPipe.prototype.transform = function (value, args) { if (parseInt(value, 10) >= 0) { value = this.formatBytes(+value, +args); } return value; }; ByteFormatPipe.prototype.formatBytes = function (bytes, decimals) { if (bytes === 0) { return '0 ' + this.unit; } var B = this.unit.charAt(0); var k = 1024; var dm = decimals || 2; var sizes = [this.unit, 'K' + B, 'M' + B, 'G' + B, 'T' + B, 'P' + B, 'E' + B, 'Z' + B, 'Y' + B]; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; }; ByteFormatPipe.ctorParameters = function () { return [ { type: FileInputConfig, decorators: [{ type: Optional }, { type: Inject, args: [NGX_MAT_FILE_INPUT_CONFIG,] }] } ]; }; ByteFormatPipe = __decorate([ Pipe({ name: 'byteFormat' }), __param(0, Optional()), __param(0, Inject(NGX_MAT_FILE_INPUT_CONFIG)), __metadata("design:paramtypes", [FileInputConfig]) ], ByteFormatPipe); return ByteFormatPipe; }()); var MaterialFileInputModule = /** @class */ (function () { function MaterialFileInputModule() { } MaterialFileInputModule = __decorate([ NgModule({ declarations: [FileInputComponent, ByteFormatPipe], providers: [FocusMonitor], exports: [FileInputComponent, ByteFormatPipe] }) ], MaterialFileInputModule); return MaterialFileInputModule; }()); var FileValidator; (function (FileValidator) { /** * Function to control content of files * * @param bytes max number of bytes allowed * * @returns */ function maxContentSize(bytes) { return function (control) { var size = control && control.value ? control.value.files.map(function (f) { return f.size; }).reduce(function (acc, i) { return acc + i; }, 0) : 0; var condition = bytes >= size; return condition ? null : { maxContentSize: { actualSize: size, maxSize: bytes } }; }; } FileValidator.maxContentSize = maxContentSize; /** * * @description Handles allowed file types by controlling whether some specific extensions matches with the uploaded file type * @export * @param {string[]} extensions * @returns {ValidatorFn} */ function allowedExtensions(extensions) { return function (control) { var allowed = control && control.value && control.value.files.every(function (file) { var fileNameSplit = file.name.split('.'); var extension = fileNameSplit[fileNameSplit.length - 1]; var foundIndex = extensions.indexOf(extension); return foundIndex !== -1; }); return allowed ? null : { allowedExtensions: extensions }; }; } FileValidator.allowedExtensions = allowedExtensions; })(FileValidator || (FileValidator = {})); /** * Generated bundle index. Do not edit. */ export { ByteFormatPipe, FileInput, FileInputComponent, FileInputConfig, FileValidator, MaterialFileInputModule, NGX_MAT_FILE_INPUT_CONFIG, FileInputBase as ɵa, FileInputMixinBase as ɵb }; //# sourceMappingURL=ngx-mat-file-input.js.map