UNPKG

mat-contenteditable

Version:

Angular contenteditable directive for Angular forms and Material Design

1,019 lines (1,004 loc) 92.7 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/material/form-field'), require('@angular/forms'), require('@angular/material/core'), require('@angular/cdk/coercion'), require('rxjs'), require('@angular/material')) : typeof define === 'function' && define.amd ? define('mat-contenteditable', ['exports', '@angular/core', '@angular/material/form-field', '@angular/forms', '@angular/material/core', '@angular/cdk/coercion', 'rxjs', '@angular/material'], factory) : (factory((global['mat-contenteditable'] = {}),global.ng.core,global.ng.material['form-field'],global.ng.forms,global.ng.material.core,global.ng.cdk.coercion,global.rxjs,global.ng.material)); }(this, (function (exports,core,formField,forms,core$1,coercion,rxjs,material) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * \@docs-private */ var /** * \@docs-private */ MatInputBase = /** @class */ (function () { function MatInputBase(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) { this._defaultErrorStateMatcher = _defaultErrorStateMatcher; this._parentForm = _parentForm; this._parentFormGroup = _parentFormGroup; this.ngControl = ngControl; } return MatInputBase; }()); /** @type {?} */ var _MatInputMixinBase = core$1.mixinErrorState(MatInputBase); var MatContenteditableDirective = /** @class */ (function (_super) { __extends(MatContenteditableDirective, _super); function MatContenteditableDirective(elementRef, renderer, ngControl, _parentForm, _parentFormGroup, _defaultErrorStateMatcher) { var _this = _super.call(this, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) || this; _this.elementRef = elementRef; _this.renderer = renderer; _this.ngControl = ngControl; _this.stateChanges = new rxjs.Subject(); _this.id = "mat-input-" + MatContenteditableDirective.nextId++; _this.focused = false; _this.contentEmpty = ['<br>', '<div><br></div>']; _this._required = false; _this._disabled = false; _this.controlType = 'mat-input'; _this.describedBy = ''; _this.propValueAccessor = 'innerHTML'; // Setting the value accessor directly (instead of using // the providers) to avoid running into a circular import. if (_this.ngControl != null) { _this.ngControl.valueAccessor = _this; } return _this; } Object.defineProperty(MatContenteditableDirective.prototype, "value", { get: /** * @return {?} */ function () { return this.elementRef.nativeElement[this.propValueAccessor]; }, set: /** * @param {?} value * @return {?} */ function (value) { if (value !== this.value) { this.elementRef.nativeElement[this.propValueAccessor] = value; this.stateChanges.next(); } }, enumerable: true, configurable: true }); Object.defineProperty(MatContenteditableDirective.prototype, "placeholder", { get: /** * @return {?} */ function () { return this._placeholder; }, set: /** * @param {?} plh * @return {?} */ function (plh) { this._placeholder = plh; this.stateChanges.next(); }, enumerable: true, configurable: true }); Object.defineProperty(MatContenteditableDirective.prototype, "empty", { get: /** * @return {?} */ function () { return !this.value || this.contentEmpty.includes(this.value); }, enumerable: true, configurable: true }); Object.defineProperty(MatContenteditableDirective.prototype, "shouldLabelFloat", { get: /** * @return {?} */ function () { return this.focused || !this.empty; }, enumerable: true, configurable: true }); Object.defineProperty(MatContenteditableDirective.prototype, "required", { get: /** * @return {?} */ function () { return this._required; }, set: /** * @param {?} req * @return {?} */ function (req) { this._required = coercion.coerceBooleanProperty(req); this.stateChanges.next(); }, enumerable: true, configurable: true }); Object.defineProperty(MatContenteditableDirective.prototype, "disabled", { get: /** * @return {?} */ function () { return this._disabled; }, set: /** * @param {?} dis * @return {?} */ function (dis) { this._disabled = coercion.coerceBooleanProperty(dis); this.stateChanges.next(); }, enumerable: true, configurable: true }); /** * @return {?} */ MatContenteditableDirective.prototype.ngDoCheck = /** * @return {?} */ 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(); } }; /** * @return {?} */ MatContenteditableDirective.prototype.callOnChange = /** * @return {?} */ function () { if (typeof this.onChange === 'function') { this.onChange(this.elementRef.nativeElement[this.propValueAccessor]); } }; /** * @return {?} */ MatContenteditableDirective.prototype.callOnFocused = /** * @return {?} */ function () { if (this.focused !== true) { this.focused = true; this.stateChanges.next(); } }; /** * @return {?} */ MatContenteditableDirective.prototype.callOnTouched = /** * @return {?} */ function () { if (typeof this.onTouched === 'function') { this.onTouched(); } if (this.focused !== false) { this.focused = false; this.stateChanges.next(); } }; /** * @param {?} ids * @return {?} */ MatContenteditableDirective.prototype.setDescribedByIds = /** * @param {?} ids * @return {?} */ function (ids) { this.describedBy = ids.join(' '); }; /** * @return {?} */ MatContenteditableDirective.prototype.onContainerClick = /** * @return {?} */ function () { this.elementRef.nativeElement.focus(); }; /** * Writes a new value to the element. * This method will be called by the forms API to write * to the view when programmatic (model -> view) changes are requested. * * See: [ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor#members) */ /** * Writes a new value to the element. * This method will be called by the forms API to write * to the view when programmatic (model -> view) changes are requested. * * See: [ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor#members) * @param {?} value * @return {?} */ MatContenteditableDirective.prototype.writeValue = /** * Writes a new value to the element. * This method will be called by the forms API to write * to the view when programmatic (model -> view) changes are requested. * * See: [ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor#members) * @param {?} value * @return {?} */ function (value) { /** @type {?} */ var normalizedValue = value == null ? '' : value; this.renderer.setProperty(this.elementRef.nativeElement, this.propValueAccessor, normalizedValue); }; /** * Registers a callback function that should be called when * the control's value changes in the UI. * * This is called by the forms API on initialization so it can update * the form model when values propagate from the view (view -> model). */ /** * Registers a callback function that should be called when * the control's value changes in the UI. * * This is called by the forms API on initialization so it can update * the form model when values propagate from the view (view -> model). * @param {?} fn * @return {?} */ MatContenteditableDirective.prototype.registerOnChange = /** * Registers a callback function that should be called when * the control's value changes in the UI. * * This is called by the forms API on initialization so it can update * the form model when values propagate from the view (view -> model). * @param {?} fn * @return {?} */ function (fn) { this.onChange = fn; }; /** * Registers a callback function that should be called when the control receives a blur event. * This is called by the forms API on initialization so it can update the form model on blur. */ /** * Registers a callback function that should be called when the control receives a blur event. * This is called by the forms API on initialization so it can update the form model on blur. * @param {?} fn * @return {?} */ MatContenteditableDirective.prototype.registerOnTouched = /** * Registers a callback function that should be called when the control receives a blur event. * This is called by the forms API on initialization so it can update the form model on blur. * @param {?} fn * @return {?} */ function (fn) { this.onTouched = fn; }; /** * This function is called by the forms API when the control status changes to or from "DISABLED". * Depending on the value, it should enable or disable the appropriate DOM element. */ /** * This function is called by the forms API when the control status changes to or from "DISABLED". * Depending on the value, it should enable or disable the appropriate DOM element. * @param {?} isDisabled * @return {?} */ MatContenteditableDirective.prototype.setDisabledState = /** * This function is called by the forms API when the control status changes to or from "DISABLED". * Depending on the value, it should enable or disable the appropriate DOM element. * @param {?} isDisabled * @return {?} */ function (isDisabled) { if (isDisabled) { this.renderer.setAttribute(this.elementRef.nativeElement, 'disabled', 'true'); this.removeDisabledState = this.renderer.listen(this.elementRef.nativeElement, 'keydown', this.listenerDisabledState); } else { if (this.removeDisabledState) { this.renderer.removeAttribute(this.elementRef.nativeElement, 'disabled'); this.removeDisabledState(); } } }; /** * @param {?} e * @return {?} */ MatContenteditableDirective.prototype.listenerDisabledState = /** * @param {?} e * @return {?} */ function (e) { e.preventDefault(); }; /** * Implemented as part of MatFormFieldControl. * See https://material.angular.io/guide/creating-a-custom-form-field-control */ MatContenteditableDirective.nextId = 0; MatContenteditableDirective.decorators = [ { type: core.Directive, args: [{ selector: '[contenteditable]', providers: [ { provide: formField.MatFormFieldControl, useExisting: MatContenteditableDirective }, ] },] } ]; /** @nocollapse */ MatContenteditableDirective.ctorParameters = function () { return [ { type: core.ElementRef }, { type: core.Renderer2 }, { type: forms.NgControl, decorators: [{ type: core.Optional }, { type: core.Self }] }, { type: forms.NgForm, decorators: [{ type: core.Optional }] }, { type: forms.FormGroupDirective, decorators: [{ type: core.Optional }] }, { type: core$1.ErrorStateMatcher } ]; }; MatContenteditableDirective.propDecorators = { value: [{ type: core.Input }], id: [{ type: core.HostBinding }], placeholder: [{ type: core.Input }], contentEmpty: [{ type: core.Input }], required: [{ type: core.Input }], disabled: [{ type: core.Input }], errorState: [{ type: core.HostBinding, args: ['attr.aria-invalid',] }], errorStateMatcher: [{ type: core.Input }], describedBy: [{ type: core.HostBinding, args: ['attr.aria-describedby',] }], propValueAccessor: [{ type: core.Input }], callOnChange: [{ type: core.HostListener, args: ['input',] }], callOnFocused: [{ type: core.HostListener, args: ['focus',] }], callOnTouched: [{ type: core.HostListener, args: ['blur',] }] }; return MatContenteditableDirective; }(_MatInputMixinBase)); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var MatCkeditorDirective = /** @class */ (function (_super) { __extends(MatCkeditorDirective, _super); function MatCkeditorDirective( // @Host() @Self() @Optional() public editor: CKEditorComponent, viewRef, ngControl, _parentForm, _parentFormGroup, _defaultErrorStateMatcher) { var _this = _super.call(this, _defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl) || this; _this.viewRef = viewRef; _this.ngControl = ngControl; _this.stateChanges = new rxjs.Subject(); _this.id = "mat-input-" + MatCkeditorDirective.nextId++; // Need support from Ckeditor _this.placeholder = ''; _this.contentEmpty = ['<br>', '<p>&nbsp;</p>']; _this.focused = false; _this.required = false; _this.controlType = 'mat-input'; _this.describedBy = ''; return _this; } Object.defineProperty(MatCkeditorDirective.prototype, "value", { get: /** * @return {?} */ function () { return !!this.editor.editorInstance && this.editor.editorInstance.getData(); }, set: /** * @param {?} value * @return {?} */ function (value) { if (value !== this.value) { this.editor.data = value; this.stateChanges.next(); } }, enumerable: true, configurable: true }); Object.defineProperty(MatCkeditorDirective.prototype, "empty", { get: /** * @return {?} */ function () { return !this.value || this.contentEmpty.includes(this.value); }, enumerable: true, configurable: true }); Object.defineProperty(MatCkeditorDirective.prototype, "shouldLabelFloat", { get: /** * @return {?} */ function () { return this.focused || !this.empty; }, enumerable: true, configurable: true }); Object.defineProperty(MatCkeditorDirective.prototype, "disabled", { get: /** * @return {?} */ function () { return this.editor.disabled; }, set: /** * @param {?} isDisabled * @return {?} */ function (isDisabled) { this.editor.setDisabledState(isDisabled); this.stateChanges.next(); }, enumerable: true, configurable: true }); /** * @return {?} */ MatCkeditorDirective.prototype.ngOnInit = /** * @return {?} */ function () { var _this = this; // Can't use injection to get component reference // https://github.com/angular/angular/issues/8277 this.editor = this.viewRef['_data'].componentView.component; this.editor.blur.subscribe(function () { _this.focused = false; _this.stateChanges.next(); }); this.editor.focus.subscribe(function () { _this.focused = true; _this.stateChanges.next(); }); }; /** * @return {?} */ MatCkeditorDirective.prototype.ngDoCheck = /** * @return {?} */ 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(); } }; /** * @param {?} ids * @return {?} */ MatCkeditorDirective.prototype.setDescribedByIds = /** * @param {?} ids * @return {?} */ function (ids) { this.describedBy = ids.join(' '); }; /** * @return {?} */ MatCkeditorDirective.prototype.onContainerClick = /** * @return {?} */ function () { if (this.editor.editorInstance) { this.editor.editorInstance.editing.view.focus(); this.stateChanges.next(); } }; /** * Implemented as part of MatFormFieldControl. * See https://material.angular.io/guide/creating-a-custom-form-field-control */ MatCkeditorDirective.nextId = 0; MatCkeditorDirective.decorators = [ { type: core.Directive, args: [{ selector: '[matCkeditor]', providers: [ { provide: material.MatFormFieldControl, useExisting: MatCkeditorDirective }, ] },] } ]; /** @nocollapse */ MatCkeditorDirective.ctorParameters = function () { return [ { type: core.ViewContainerRef }, { type: forms.NgControl, decorators: [{ type: core.Optional }, { type: core.Self }] }, { type: forms.NgForm, decorators: [{ type: core.Optional }] }, { type: forms.FormGroupDirective, decorators: [{ type: core.Optional }] }, { type: material.ErrorStateMatcher } ]; }; MatCkeditorDirective.propDecorators = { value: [{ type: core.Input }], id: [{ type: core.HostBinding }], placeholder: [{ type: core.Input }], contentEmpty: [{ type: core.Input }], required: [{ type: core.Input }], disabled: [{ type: core.Input }], errorState: [{ type: core.HostBinding, args: ['attr.aria-invalid',] }], errorStateMatcher: [{ type: core.Input }], describedBy: [{ type: core.HostBinding, args: ['attr.aria-describedby',] }] }; return MatCkeditorDirective; }(_MatInputMixinBase)); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var MatCkeditorBalloonDirective = /** @class */ (function (_super) { __extends(MatCkeditorBalloonDirective, _super); function MatCkeditorBalloonDirective() { return _super !== null && _super.apply(this, arguments) || this; } Object.defineProperty(MatCkeditorBalloonDirective.prototype, "toolbar", { set: /** * @param {?} show * @return {?} */ function (show) { if (this.editor && show !== this.toolbarOpen) { /** @type {?} */ var balloon = this.editor.editorInstance.plugins.get('BalloonToolbar'); if (show) { this.showToolbar(balloon); } else { balloon.hide(); this.toolbarOpen = false; } } }, enumerable: true, configurable: true }); /** * @return {?} */ MatCkeditorBalloonDirective.prototype.ngOnInit = /** * @return {?} */ function () { var _this = this; _super.prototype.ngOnInit.call(this); this.editor.ready.subscribe(function (editor) { /** @type {?} */ var balloon = editor.plugins.get('BalloonToolbar'); balloon.stopListening(editor.model.document.selection, 'change:range'); balloon.stopListening(balloon, '_selectionChangeDebounced'); }); this.editor.focus.subscribe(function () { if (_this.toolbarOpen) { /** @type {?} */ var balloon = _this.editor.editorInstance.plugins.get('BalloonToolbar'); _this.showToolbar(balloon); } }); }; /** * @param {?} balloon * @return {?} */ MatCkeditorBalloonDirective.prototype.showToolbar = /** * @param {?} balloon * @return {?} */ function (balloon) { if (!balloon._balloon.hasView(balloon.toolbarView)) { balloon.listenTo(this.editor.editorInstance.ui, 'update', function () { balloon._balloon.updatePosition(balloon._getBalloonPositionData()); }); balloon._balloon.add({ view: balloon.toolbarView, position: balloon._getBalloonPositionData(), balloonClassName: 'ck-toolbar-container' }); this.toolbarOpen = true; } }; MatCkeditorBalloonDirective.decorators = [ { type: core.Directive, args: [{ selector: '[matCkeditorBalloon]', providers: [ { provide: formField.MatFormFieldControl, useExisting: MatCkeditorBalloonDirective }, ] },] } ]; MatCkeditorBalloonDirective.propDecorators = { toolbar: [{ type: core.Input }] }; return MatCkeditorBalloonDirective; }(MatCkeditorDirective)); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var FormFieldSizerDirective = /** @class */ (function () { function FormFieldSizerDirective(renderer, elementRef) { this.renderer = renderer; this.elementRef = elementRef; } /** * @return {?} */ FormFieldSizerDirective.prototype.ngAfterContentInit = /** * @return {?} */ function () { this.updateSize(); }; /** * @return {?} */ FormFieldSizerDirective.prototype.updateSize = /** * @return {?} */ function () { var _this = this; /** @type {?} */ var infix = this.getElement('mat-form-field-infix'); this.renderer.removeStyle(infix, 'min-height'); setTimeout(function () { /** @type {?} */ var wrapper = _this.getElement('mat-form-field-wrapper'); /** @type {?} */ var offset = _this.elementRef.nativeElement.offsetHeight - wrapper.offsetHeight - parseFloat(getComputedStyle(wrapper).marginTop) - parseFloat(getComputedStyle(wrapper).marginBottom) + parseFloat(getComputedStyle(infix).height); _this.renderer.setStyle(infix, 'min-height', offset + "px"); }); }; /** * @param {?} name * @return {?} */ FormFieldSizerDirective.prototype.getElement = /** * @param {?} name * @return {?} */ function (name) { return this.elementRef.nativeElement.getElementsByClassName(name).item(0); }; FormFieldSizerDirective.decorators = [ { type: core.Directive, args: [{ selector: '[formFieldSizer]' },] } ]; /** @nocollapse */ FormFieldSizerDirective.ctorParameters = function () { return [ { type: core.Renderer2 }, { type: core.ElementRef } ]; }; return FormFieldSizerDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var MatContenteditableModule = /** @class */ (function () { function MatContenteditableModule() { } MatContenteditableModule.decorators = [ { type: core.NgModule, args: [{ imports: [], declarations: [MatContenteditableDirective, MatCkeditorDirective, MatCkeditorBalloonDirective, FormFieldSizerDirective], exports: [MatContenteditableDirective, MatCkeditorDirective, MatCkeditorBalloonDirective, FormFieldSizerDirective], },] } ]; return MatContenteditableModule; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @param {?} html * @return {?} */ function getText(html) { if (html) { /** @type {?} */ var element = document.createElement('span'); element.innerHTML = html; return element.textContent.replace(/\s/g, ''); } return ''; } /** * \@description * Provides a set of built-in validators that can be used by form controls. * * A validator is a function that processes a `FormControl` or collection of * controls and returns an error map or null. A null map means that validation has passed. * * @see [Form Validation](/guide/form-validation) * * \@publicApi */ var /** * \@description * Provides a set of built-in validators that can be used by form controls. * * A validator is a function that processes a `FormControl` or collection of * controls and returns an error map or null. A null map means that validation has passed. * * @see [Form Validation](/guide/form-validation) * * \@publicApi */ HtmlValidators = /** @class */ (function () { function HtmlValidators() { } /** * @description * Validator that requires the control have a non-empty value. * * @usageNotes * * ### Validate that the field is non-empty * * ```typescript * const control = new FormControl('', Validators.required); * * console.log(control.errors); // {required: true} * ``` * * @returns An error map with the `required` property * if the validation check fails, otherwise `null`. * */ /** * \@description * Validator that requires the control have a non-empty value. * * \@usageNotes * * ### Validate that the field is non-empty * * ```typescript * const control = new FormControl('', Validators.required); * * console.log(control.errors); // {required: true} * ``` * * @param {?} control * @return {?} An error map with the `required` property * if the validation check fails, otherwise `null`. * */ HtmlValidators.required = /** * \@description * Validator that requires the control have a non-empty value. * * \@usageNotes * * ### Validate that the field is non-empty * * ```typescript * const control = new FormControl('', Validators.required); * * console.log(control.errors); // {required: true} * ``` * * @param {?} control * @return {?} An error map with the `required` property * if the validation check fails, otherwise `null`. * */ function (control) { /** @type {?} */ var text = getText(control.value); return text ? null : { 'required': true }; }; /** * @description * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the * the HTML5 `minlength` attribute. * * @usageNotes * * ### Validate that the field has a minimum of 3 characters * * ```typescript * const control = new FormControl('ng', Validators.minLength(3)); * * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}} * ``` * * ```html * <input minlength="5"> * ``` * * @returns A validator function that returns an error map with the * `minlength` if the validation check fails, otherwise `null`. */ /** * \@description * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the * the HTML5 `minlength` attribute. * * \@usageNotes * * ### Validate that the field has a minimum of 3 characters * * ```typescript * const control = new FormControl('ng', Validators.minLength(3)); * * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}} * ``` * * ```html * <input minlength="5"> * ``` * * @param {?} minLength * @return {?} A validator function that returns an error map with the * `minlength` if the validation check fails, otherwise `null`. */ HtmlValidators.minLength = /** * \@description * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the * the HTML5 `minlength` attribute. * * \@usageNotes * * ### Validate that the field has a minimum of 3 characters * * ```typescript * const control = new FormControl('ng', Validators.minLength(3)); * * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}} * ``` * * ```html * <input minlength="5"> * ``` * * @param {?} minLength * @return {?} A validator function that returns an error map with the * `minlength` if the validation check fails, otherwise `null`. */ function (minLength) { /** @type {?} */ var fn = function (control) { /** @type {?} */ var text = getText(control.value); if (text) { return text.length < minLength ? { 'minlength': { 'requiredLength': minLength, 'actualLength': text.length } } : null; } return null; // don't validate empty values to allow optional controls }; return fn; }; /** * @description * Validator that requires the length of the control's value to be less than or equal * to the provided maximum length. This validator is also provided by default if you use the * the HTML5 `maxlength` attribute. * * @usageNotes * * ### Validate that the field has maximum of 5 characters * * ```typescript * const control = new FormControl('Angular', Validators.maxLength(5)); * * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}} * ``` * * ```html * <input maxlength="5"> * ``` * * @returns A validator function that returns an error map with the * `maxlength` property if the validation check fails, otherwise `null`. */ /** * \@description * Validator that requires the length of the control's value to be less than or equal * to the provided maximum length. This validator is also provided by default if you use the * the HTML5 `maxlength` attribute. * * \@usageNotes * * ### Validate that the field has maximum of 5 characters * * ```typescript * const control = new FormControl('Angular', Validators.maxLength(5)); * * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}} * ``` * * ```html * <input maxlength="5"> * ``` * * @param {?} maxLength * @return {?} A validator function that returns an error map with the * `maxlength` property if the validation check fails, otherwise `null`. */ HtmlValidators.maxLength = /** * \@description * Validator that requires the length of the control's value to be less than or equal * to the provided maximum length. This validator is also provided by default if you use the * the HTML5 `maxlength` attribute. * * \@usageNotes * * ### Validate that the field has maximum of 5 characters * * ```typescript * const control = new FormControl('Angular', Validators.maxLength(5)); * * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}} * ``` * * ```html * <input maxlength="5"> * ``` * * @param {?} maxLength * @return {?} A validator function that returns an error map with the * `maxlength` property if the validation check fails, otherwise `null`. */ function (maxLength) { /** @type {?} */ var fn = function (control) { /** @type {?} */ var text = getText(control.value); return text.length > maxLength ? { 'maxlength': { 'requiredLength': maxLength, 'actualLength': text.length } } : null; }; return fn; }; return HtmlValidators; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ exports._MatInputMixinBase = _MatInputMixinBase; exports.MatContenteditableDirective = MatContenteditableDirective; exports.MatCkeditorDirective = MatCkeditorDirective; exports.MatCkeditorBalloonDirective = MatCkeditorBalloonDirective; exports.FormFieldSizerDirective = FormFieldSizerDirective; exports.MatContenteditableModule = MatContenteditableModule; exports.HtmlValidators = HtmlValidators; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0LWNvbnRlbnRlZGl0YWJsZS51bWQuanMubWFwIiwic291cmNlcyI6WyJub2RlX21vZHVsZXMvdHNsaWIvdHNsaWIuZXM2LmpzIiwibmc6Ly9tYXQtY29udGVudGVkaXRhYmxlL2xpYi9tYXQtY29udGVudGVkaXRhYmxlLmRpcmVjdGl2ZS50cyIsIm5nOi8vbWF0LWNvbnRlbnRlZGl0YWJsZS9saWIvbWF0LWNrZWRpdG9yLmRpcmVjdGl2ZS50cyIsIm5nOi8vbWF0LWNvbnRlbnRlZGl0YWJsZS9saWIvbWF0LWNrZWRpdG9yLWJhbGxvb24uZGlyZWN0aXZlLnRzIiwibmc6Ly9tYXQtY29udGVudGVkaXRhYmxlL2xpYi9mb3JtLWZpZWxkLXNpemVyLmRpcmVjdGl2ZS50cyIsIm5nOi8vbWF0LWNvbnRlbnRlZGl0YWJsZS9saWIvbWF0LWNvbnRlbnRlZGl0YWJsZS5tb2R1bGUudHMiLCJuZzovL21hdC1jb250ZW50ZWRpdGFibGUvbGliL3ZhbGlkYXRvcnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyohICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbkNvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpOyB5b3UgbWF5IG5vdCB1c2VcclxudGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGVcclxuTGljZW5zZSBhdCBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcclxuXHJcblRISVMgQ09ERSBJUyBQUk9WSURFRCBPTiBBTiAqQVMgSVMqIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTllcclxuS0lORCwgRUlUSEVSIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIFdJVEhPVVQgTElNSVRBVElPTiBBTlkgSU1QTElFRFxyXG5XQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgVElUTEUsIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLFxyXG5NRVJDSEFOVEFCTElUWSBPUiBOT04tSU5GUklOR0VNRU5ULlxyXG5cclxuU2VlIHRoZSBBcGFjaGUgVmVyc2lvbiAyLjAgTGljZW5zZSBmb3Igc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zXHJcbmFuZCBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogKi9cclxuLyogZ2xvYmFsIFJlZmxlY3QsIFByb21pc2UgKi9cclxuXHJcbnZhciBleHRlbmRTdGF0aWNzID0gZnVuY3Rpb24oZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyA9IE9iamVjdC5zZXRQcm90b3R5cGVPZiB8fFxyXG4gICAgICAgICh7IF9fcHJvdG9fXzogW10gfSBpbnN0YW5jZW9mIEFycmF5ICYmIGZ1bmN0aW9uIChkLCBiKSB7IGQuX19wcm90b19fID0gYjsgfSkgfHxcclxuICAgICAgICBmdW5jdGlvbiAoZCwgYikgeyBmb3IgKHZhciBwIGluIGIpIGlmIChiLmhhc093blByb3BlcnR5KHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbmV4cG9ydCB2YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIGlmIChlLmluZGV4T2YocFtpXSkgPCAwKVxyXG4gICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgIHJldHVybiB0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYykge1xyXG4gICAgdmFyIGMgPSBhcmd1bWVudHMubGVuZ3RoLCByID0gYyA8IDMgPyB0YXJnZXQgOiBkZXNjID09PSBudWxsID8gZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBrZXkpIDogZGVzYywgZDtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSA9PT0gXCJmdW5jdGlvblwiKSByID0gUmVmbGVjdC5kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYyk7XHJcbiAgICBlbHNlIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSBpZiAoZCA9IGRlY29yYXRvcnNbaV0pIHIgPSAoYyA8IDMgPyBkKHIpIDogYyA+IDMgPyBkKHRhcmdldCwga2V5LCByKSA6IGQodGFyZ2V0LCBrZXkpKSB8fCByO1xyXG4gICAgcmV0dXJuIGMgPiAzICYmIHIgJiYgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCByKSwgcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcGFyYW0ocGFyYW1JbmRleCwgZGVjb3JhdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCwga2V5KSB7IGRlY29yYXRvcih0YXJnZXQsIGtleSwgcGFyYW1JbmRleCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fbWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpIHtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5tZXRhZGF0YSA9PT0gXCJmdW5jdGlvblwiKSByZXR1cm4gUmVmbGVjdC5tZXRhZGF0YShtZXRhZGF0YUtleSwgbWV0YWRhdGFWYWx1ZSk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBuZXcgUChmdW5jdGlvbiAocmVzb2x2ZSkgeyByZXNvbHZlKHJlc3VsdC52YWx1ZSk7IH0pLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZ2VuZXJhdG9yKHRoaXNBcmcsIGJvZHkpIHtcclxuICAgIHZhciBfID0geyBsYWJlbDogMCwgc2VudDogZnVuY3Rpb24oKSB7IGlmICh0WzBdICYgMSkgdGhyb3cgdFsxXTsgcmV0dXJuIHRbMV07IH0sIHRyeXM6IFtdLCBvcHM6IFtdIH0sIGYsIHksIHQsIGc7XHJcbiAgICByZXR1cm4gZyA9IHsgbmV4dDogdmVyYigwKSwgXCJ0aHJvd1wiOiB2ZXJiKDEpLCBcInJldHVyblwiOiB2ZXJiKDIpIH0sIHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiAoZ1tTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzOyB9KSwgZztcclxuICAgIGZ1bmN0aW9uIHZlcmIobikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIHN0ZXAoW24sIHZdKTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc3RlcChvcCkge1xyXG4gICAgICAgIGlmIChmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR2VuZXJhdG9yIGlzIGFscmVhZHkgZXhlY3V0aW5nLlwiKTtcclxuICAgICAgICB3aGlsZSAoXykgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKGYgPSAxLCB5ICYmICh0ID0gb3BbMF0gJiAyID8geVtcInJldHVyblwiXSA6IG9wWzBdID8geVtcInRocm93XCJdIHx8ICgodCA9IHlbXCJyZXR1cm5cIl0pICYmIHQuY2FsbCh5KSwgMCkgOiB5Lm5leHQpICYmICEodCA9IHQuY2FsbCh5LCBvcFsxXSkpLmRvbmUpIHJldHVybiB0O1xyXG4gICAgICAgICAgICBpZiAoeSA9IDAsIHQpIG9wID0gW29wWzBdICYgMiwgdC52YWx1ZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAob3BbMF0pIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDogY2FzZSAxOiB0ID0gb3A7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA0OiBfLmxhYmVsKys7IHJldHVybiB7IHZhbHVlOiBvcFsxXSwgZG9uZTogZmFsc2UgfTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNTogXy5sYWJlbCsrOyB5ID0gb3BbMV07IG9wID0gWzBdOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNzogb3AgPSBfLm9wcy5wb3AoKTsgXy50cnlzLnBvcCgpOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEodCA9IF8udHJ5cywgdCA9IHQubGVuZ3RoID4gMCAmJiB0W3QubGVuZ3RoIC0gMV0pICYmIChvcFswXSA9PT0gNiB8fCBvcFswXSA9PT0gMikpIHsgXyA9IDA7IGNvbnRpbnVlOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSAzICYmICghdCB8fCAob3BbMV0gPiB0WzBdICYmIG9wWzFdIDwgdFszXSkpKSB7IF8ubGFiZWwgPSBvcFsxXTsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDYgJiYgXy5sYWJlbCA8IHRbMV0pIHsgXy5sYWJlbCA9IHRbMV07IHQgPSBvcDsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodCAmJiBfLmxhYmVsIDwgdFsyXSkgeyBfLmxhYmVsID0gdFsyXTsgXy5vcHMucHVzaChvcCk7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRbMl0pIF8ub3BzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgb3AgPSBib2R5LmNhbGwodGhpc0FyZywgXyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkgeyBvcCA9IFs2LCBlXTsgeSA9IDA7IH0gZmluYWxseSB7IGYgPSB0ID0gMDsgfVxyXG4gICAgICAgIGlmIChvcFswXSAmIDUpIHRocm93IG9wWzFdOyByZXR1cm4geyB2YWx1ZTogb3BbMF0gPyBvcFsxXSA6IHZvaWQgMCwgZG9uZTogdHJ1ZSB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHBvcnRTdGFyKG0sIGV4cG9ydHMpIHtcclxuICAgIGZvciAodmFyIHAgaW4gbSkgaWYgKCFleHBvcnRzLmhhc093blByb3BlcnR5KHApKSBleHBvcnRzW3BdID0gbVtwXTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fdmFsdWVzKG8pIHtcclxuICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9bU3ltYm9sLml0ZXJhdG9yXSwgaSA9IDA7XHJcbiAgICBpZiAobSkgcmV0dXJuIG0uY2FsbChvKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgICAgbmV4dDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAobyAmJiBpID49IG8ubGVuZ3RoKSBvID0gdm9pZCAwO1xyXG4gICAgICAgICAgICByZXR1cm4geyB2YWx1ZTogbyAmJiBvW2krK10sIGRvbmU6ICFvIH07XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVhZChvLCBuKSB7XHJcbiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07XHJcbiAgICBpZiAoIW0pIHJldHVybiBvO1xyXG4gICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7XHJcbiAgICB0cnkge1xyXG4gICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpO1xyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9XHJcbiAgICBmaW5hbGx5IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVtcInJldHVyblwiXSkpIG0uY2FsbChpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZmluYWxseSB7IGlmIChlKSB0aHJvdyBlLmVycm9yOyB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXI7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZCgpIHtcclxuICAgIGZvciAodmFyIGFyID0gW10sIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTtcclxuICAgIHJldHVybiBhcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXdhaXQodikge1xyXG4gICA