@ngxmc/file-input
Version:
Angular Material File Input
334 lines (326 loc) • 18.1 kB
JavaScript
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import * as i0 from '@angular/core';
import { Directive, viewChild, input, forwardRef, Input, Optional, Self, ViewEncapsulation, Component } from '@angular/core';
import * as i5 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldControl } from '@angular/material/form-field';
import * as i4 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import { Subject } from 'rxjs';
import * as i1 from '@angular/cdk/platform';
import * as i2 from '@angular/forms';
import * as i3 from '@angular/material/core';
let nextUniqueId = 0;
class NgxMatInputMixinBase {
constructor(_defaultErrorStateMatcher, _parentForm, _parentFormGroup,
/** @docs-private */
ngControl) {
this._defaultErrorStateMatcher = _defaultErrorStateMatcher;
this._parentForm = _parentForm;
this._parentFormGroup = _parentFormGroup;
this.ngControl = ngControl;
this.stateChanges = new Subject();
}
}
class NgxMatFileInputIcon {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: NgxMatFileInputIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.4", type: NgxMatFileInputIcon, isStandalone: true, selector: "[ngxMatFileInputIcon]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: NgxMatFileInputIcon, decorators: [{
type: Directive,
args: [{
selector: '[ngxMatFileInputIcon]',
}]
}] });
class NgxMatFileInputComponent extends NgxMatInputMixinBase {
get disabled() {
if (this.ngControl && this.ngControl.disabled !== null) {
return this.ngControl.disabled;
}
return this._disabled;
}
set disabled(value) {
this._disabled = coerceBooleanProperty(value);
if (this.focused) {
this.focused = false;
this.stateChanges.next();
}
}
get id() {
return this._id;
}
set id(value) {
this._id = value || this._uid;
}
get multiple() {
return this._multiple;
}
set multiple(value) {
this._multiple = coerceBooleanProperty(value);
}
get required() {
return this._required;
}
set required(value) {
this._required = coerceBooleanProperty(value);
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
}
get readonly() {
return this._readonly;
}
set readonly(value) {
this._readonly = coerceBooleanProperty(value);
}
/**
* Limiting accepted file types
* Example: accept="image/png, image/jpeg" or accept=".png, .jpg, .jpeg" — Accept PNG or JPEG files.
*/
get accept() {
return this._accept;
}
set accept(value) {
this._accept = value;
}
constructor(_elementRef, _platform, _cd, ngControl, _parentForm, _parentFormGroup, _defaultErrorStateMatcher) {
super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);
this._elementRef = _elementRef;
this._platform = _platform;
this._cd = _cd;
this.ngControl = ngControl;
this._inputFileRef = viewChild('inputFile', ...(ngDevMode ? [{ debugName: "_inputFileRef" }] : []));
this._inputValueRef = viewChild('inputValue', ...(ngDevMode ? [{ debugName: "_inputValueRef" }] : []));
this.color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
this.fileNames = null;
this._uid = `ngx-mat-fileinput-${nextUniqueId++}`;
this.stateChanges = new Subject();
this.focused = false;
this.controlType = 'ngx-mat-file-input';
this.autofilled = false;
/** Function when touched */
this._onTouched = () => { };
/** Function when changed */
this._onChange = () => { };
this._disabled = false;
this._multiple = false;
this.placeholder = 'Choose a file';
this.separator = input(',', ...(ngDevMode ? [{ debugName: "separator" }] : []));
this._required = false;
this._readonly = true;
this.id = this.id;
if (this.ngControl) {
this.ngControl.valueAccessor = this;
}
}
ngOnChanges() {
this.stateChanges.next();
}
ngOnDestroy() {
this.stateChanges.complete();
}
ngDoCheck() {
if (this.ngControl) {
this.updateErrorState();
}
}
updateErrorState() {
const control = this.ngControl ? this.ngControl.control : null;
this.errorState = (this.errorStateMatcher ?? this._defaultErrorStateMatcher).isErrorState(control, this._parentForm);
}
// Implemented as part of ControlValueAccessor.
writeValue(value) {
this._updateInputValue(value);
}
// Implemented as part of ControlValueAccessor.
registerOnChange(fn) {
this._onChange = fn;
}
// Implemented as part of ControlValueAccessor.
registerOnTouched(fn) {
this._onTouched = fn;
}
// Implemented as part of ControlValueAccessor.
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.stateChanges.next();
}
/** Focuses the input. */
focus(options) {
this._inputValueRef().nativeElement.focus(options);
}
_focusChanged(isFocused) {
if (isFocused !== this.focused && (!this.readonly || !isFocused)) {
this.focused = isFocused;
this.stateChanges.next();
}
}
/** Mark the field as touched */
_markAsTouched() {
this._onTouched();
this._cd.markForCheck();
this.stateChanges.next();
}
_isBadInput() {
let validity = this._inputValueRef().nativeElement.validity;
return validity && validity.badInput;
}
get empty() {
return !this._inputValueRef().nativeElement.value && !this._isBadInput() && !this.autofilled;
}
get shouldLabelFloat() {
return this.focused || !this.empty;
}
setDescribedByIds(ids) {
this._ariaDescribedby = ids.join(' ');
}
openFilePicker(event) {
this._inputFileRef().nativeElement.click();
if (event) {
event.preventDefault();
event.stopPropagation();
}
this._markAsTouched();
}
handleFiles(filelist) {
if (filelist.length > 0) {
const files = new Array();
for (let i = 0; i < filelist.length; i++) {
files.push(filelist.item(i));
}
this._updateInputValue(files);
this._resetInputFile();
this._onChange(this.multiple ? files : files[0]);
}
}
/** Handles a click on the control's container. */
onContainerClick(event) { }
_resetInputFile() {
this._inputFileRef().nativeElement.value = '';
}
_updateInputValue(files) {
let text = null;
if (files) {
if (Array.isArray(files)) {
text = this._multiple ? files.map((x) => x.name).join(this.separator()) : files[0].name;
}
else {
text = files.name != null ? files.name : null;
}
}
this._inputValueRef().nativeElement.value = text;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: NgxMatFileInputComponent, deps: [{ token: i0.ElementRef }, { token: i1.Platform }, { token: i0.ChangeDetectorRef }, { token: i2.NgControl, optional: true, self: true }, { token: i2.NgForm, optional: true }, { token: i2.FormGroupDirective, optional: true }, { token: i3.ErrorStateMatcher }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.4", type: NgxMatFileInputComponent, isStandalone: true, selector: "ngx-mat-file-input", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: false, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, errorStateMatcher: { classPropertyName: "errorStateMatcher", publicName: "errorStateMatcher", isSignal: false, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: false, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: false, isRequired: false, transformFunction: null } }, host: { classAttribute: "ngx-mat-file-input" }, providers: [
{
provide: MatFormFieldControl,
useExisting: forwardRef((() => NgxMatFileInputComponent)),
},
], viewQueries: [{ propertyName: "_inputFileRef", first: true, predicate: ["inputFile"], descendants: true, isSignal: true }, { propertyName: "_inputValueRef", first: true, predicate: ["inputValue"], descendants: true, isSignal: true }], exportAs: ["ngx-mat-file-input"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<input\n #inputValue\n autocomplete=\"off\"\n class=\"mat-mdc-input-element mat-mdc-form-field-input-control mdc-text-field__input\"\n [attr.id]=\"id\"\n [attr.placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [attr.readonly]=\"readonly || null\"\n [attr.aria-describedby]=\"_ariaDescribedby || null\"\n [attr.aria-invalid]=\"errorState\"\n [attr.aria-required]=\"required.toString()\"\n/>\n<div class=\"mat-mdc-form-field-suffix\">\n <button\n matSuffix\n mat-icon-button\n [color]=\"color()\"\n class=\"button-browse\"\n (click)=\"openFilePicker($event)\"\n type=\"button\"\n [disabled]=\"disabled\"\n >\n <ng-content select=\"[ngxMatFileInputIcon]\">\n <mat-icon class=\"ngx-mat-file-input--default-icon\">attach_file</mat-icon>\n </ng-content>\n </button>\n</div>\n<input\n type=\"file\"\n #inputFile\n (change)=\"handleFiles($event.target.files)\"\n class=\"input-file\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n/>\n", styles: [".mat-mdc-form-field-appearance-outline .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field-appearance-outline .mat-form-field-suffix .ngx-mat-file-input--default-icon{width:1em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .ngx-mat-file-input--default-icon{display:block;width:1.5em;height:1.5em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .mat-icon-button .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .mat-icon-button .ngx-mat-file-input--default-icon{margin:auto}.ngx-mat-file-input{display:flex;line-height:18px;align-items:center}.ngx-mat-file-input .input-file{display:block;visibility:hidden;width:0;height:0}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: NgxMatFileInputComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-mat-file-input', encapsulation: ViewEncapsulation.None, host: {
class: 'ngx-mat-file-input',
}, providers: [
{
provide: MatFormFieldControl,
useExisting: forwardRef((() => NgxMatFileInputComponent)),
},
], exportAs: 'ngx-mat-file-input', imports: [MatIconModule, MatButtonModule], template: "<input\n #inputValue\n autocomplete=\"off\"\n class=\"mat-mdc-input-element mat-mdc-form-field-input-control mdc-text-field__input\"\n [attr.id]=\"id\"\n [attr.placeholder]=\"placeholder\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [attr.readonly]=\"readonly || null\"\n [attr.aria-describedby]=\"_ariaDescribedby || null\"\n [attr.aria-invalid]=\"errorState\"\n [attr.aria-required]=\"required.toString()\"\n/>\n<div class=\"mat-mdc-form-field-suffix\">\n <button\n matSuffix\n mat-icon-button\n [color]=\"color()\"\n class=\"button-browse\"\n (click)=\"openFilePicker($event)\"\n type=\"button\"\n [disabled]=\"disabled\"\n >\n <ng-content select=\"[ngxMatFileInputIcon]\">\n <mat-icon class=\"ngx-mat-file-input--default-icon\">attach_file</mat-icon>\n </ng-content>\n </button>\n</div>\n<input\n type=\"file\"\n #inputFile\n (change)=\"handleFiles($event.target.files)\"\n class=\"input-file\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n/>\n", styles: [".mat-mdc-form-field-appearance-outline .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field-appearance-outline .mat-form-field-suffix .ngx-mat-file-input--default-icon{width:1em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .ngx-mat-file-input--default-icon{display:block;width:1.5em;height:1.5em}.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-prefix .mat-icon-button .ngx-mat-file-input--default-icon,.mat-mdc-form-field:not(.mat-form-field-appearance-outline) .mat-form-field-suffix .mat-icon-button .ngx-mat-file-input--default-icon{margin:auto}.ngx-mat-file-input{display:flex;line-height:18px;align-items:center}.ngx-mat-file-input .input-file{display:block;visibility:hidden;width:0;height:0}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.Platform }, { type: i0.ChangeDetectorRef }, { type: i2.NgControl, decorators: [{
type: Optional
}, {
type: Self
}] }, { type: i2.NgForm, decorators: [{
type: Optional
}] }, { type: i2.FormGroupDirective, decorators: [{
type: Optional
}] }, { type: i3.ErrorStateMatcher }], propDecorators: { disabled: [{
type: Input
}], id: [{
type: Input
}], multiple: [{
type: Input
}], placeholder: [{
type: Input
}], required: [{
type: Input
}], errorStateMatcher: [{
type: Input
}], value: [{
type: Input
}], readonly: [{
type: Input
}], accept: [{
type: Input
}] } });
function calculFileSize(number) {
if (number < 1024) {
return number + 'bytes';
}
else if (number >= 1024 && number < 1048576) {
return (number / 1024).toFixed(1) + 'KB';
}
else if (number >= 1048576) {
return (number / 1048576).toFixed(1) + 'MB';
}
}
/**
* Validator for size of file
* @param max Max of size of file (in bytes)
*/
function MaxSizeValidator(max) {
return (ctrl) => {
max = Number(max);
if (isNaN(max)) {
throw 'MaxSizeValidator: max of size of file is invalid';
}
if (!ctrl.value)
return null;
let files = ctrl.value;
if (!Array.isArray(ctrl.value)) {
files = [ctrl.value];
}
if (!files.length)
return null;
const add = (a, b) => a + b;
const sumSize = files.map((x) => x.size).reduce(add);
if (sumSize > max) {
return {
maxSize: true,
};
}
return null;
};
}
/**
* Validator for input file accept
* @param accept Allowable type of file
*/
function AcceptValidator(accept) {
return (ctrl) => {
if (!accept) {
throw 'AcceptValidator: allowable type of file can not be empty';
}
if (ctrl.value == null)
return null;
if (!accept.includes(ctrl.value.type)) {
return {
accept: true,
};
}
return null;
};
}
/*
* Public API Surface of file-input
*/
/**
* Generated bundle index. Do not edit.
*/
export { AcceptValidator, MaxSizeValidator, NgxMatFileInputComponent, NgxMatFileInputIcon, calculFileSize };
//# sourceMappingURL=ngxmc-file-input.mjs.map