UNPKG

mat-contenteditable

Version:

Angular contenteditable directive for Angular forms and Material Design

996 lines (986 loc) 71.6 kB
import { __extends } from 'tslib'; import { Directive, ElementRef, Renderer2, HostListener, Input, HostBinding, Optional, Self, ViewContainerRef, NgModule } from '@angular/core'; import { MatFormFieldControl } from '@angular/material/form-field'; import { FormGroupDirective, NgControl, NgForm } from '@angular/forms'; import { ErrorStateMatcher, mixinErrorState } from '@angular/material/core'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { Subject } from 'rxjs'; import { MatFormFieldControl as MatFormFieldControl$1, ErrorStateMatcher as ErrorStateMatcher$1 } from '@angular/material'; /** * @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 = 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 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 = 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 = 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: Directive, args: [{ selector: '[contenteditable]', providers: [ { provide: MatFormFieldControl, useExisting: MatContenteditableDirective }, ] },] } ]; /** @nocollapse */ MatContenteditableDirective.ctorParameters = function () { return [ { type: ElementRef }, { type: Renderer2 }, { type: NgControl, decorators: [{ type: Optional }, { type: Self }] }, { type: NgForm, decorators: [{ type: Optional }] }, { type: FormGroupDirective, decorators: [{ type: Optional }] }, { type: ErrorStateMatcher } ]; }; MatContenteditableDirective.propDecorators = { value: [{ type: Input }], id: [{ type: HostBinding }], placeholder: [{ type: Input }], contentEmpty: [{ type: Input }], required: [{ type: Input }], disabled: [{ type: Input }], errorState: [{ type: HostBinding, args: ['attr.aria-invalid',] }], errorStateMatcher: [{ type: Input }], describedBy: [{ type: HostBinding, args: ['attr.aria-describedby',] }], propValueAccessor: [{ type: Input }], callOnChange: [{ type: HostListener, args: ['input',] }], callOnFocused: [{ type: HostListener, args: ['focus',] }], callOnTouched: [{ type: 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 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: Directive, args: [{ selector: '[matCkeditor]', providers: [ { provide: MatFormFieldControl$1, useExisting: MatCkeditorDirective }, ] },] } ]; /** @nocollapse */ MatCkeditorDirective.ctorParameters = function () { return [ { type: ViewContainerRef }, { type: NgControl, decorators: [{ type: Optional }, { type: Self }] }, { type: NgForm, decorators: [{ type: Optional }] }, { type: FormGroupDirective, decorators: [{ type: Optional }] }, { type: ErrorStateMatcher$1 } ]; }; MatCkeditorDirective.propDecorators = { value: [{ type: Input }], id: [{ type: HostBinding }], placeholder: [{ type: Input }], contentEmpty: [{ type: Input }], required: [{ type: Input }], disabled: [{ type: Input }], errorState: [{ type: HostBinding, args: ['attr.aria-invalid',] }], errorStateMatcher: [{ type: Input }], describedBy: [{ type: 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: Directive, args: [{ selector: '[matCkeditorBalloon]', providers: [ { provide: MatFormFieldControl, useExisting: MatCkeditorBalloonDirective }, ] },] } ]; MatCkeditorBalloonDirective.propDecorators = { toolbar: [{ type: 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: Directive, args: [{ selector: '[formFieldSizer]' },] } ]; /** @nocollapse */ FormFieldSizerDirective.ctorParameters = function () { return [ { type: Renderer2 }, { type: ElementRef } ]; }; return FormFieldSizerDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var MatContenteditableModule = /** @class */ (function () { function MatContenteditableModule() { } MatContenteditableModule.decorators = [ { type: 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 */ export { _MatInputMixinBase, MatContenteditableDirective, MatCkeditorDirective, MatCkeditorBalloonDirective, FormFieldSizerDirective, MatContenteditableModule, HtmlValidators }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0LWNvbnRlbnRlZGl0YWJsZS5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vbWF0LWNvbnRlbnRlZGl0YWJsZS9saWIvbWF0LWNvbnRlbnRlZGl0YWJsZS5kaXJlY3RpdmUudHMiLCJuZzovL21hdC1jb250ZW50ZWRpdGFibGUvbGliL21hdC1ja2VkaXRvci5kaXJlY3RpdmUudHMiLCJuZzovL21hdC1jb250ZW50ZWRpdGFibGUvbGliL21hdC1ja2VkaXRvci1iYWxsb29uLmRpcmVjdGl2ZS50cyIsIm5nOi8vbWF0LWNvbnRlbnRlZGl0YWJsZS9saWIvZm9ybS1maWVsZC1zaXplci5kaXJlY3RpdmUudHMiLCJuZzovL21hdC1jb250ZW50ZWRpdGFibGUvbGliL21hdC1jb250ZW50ZWRpdGFibGUubW9kdWxlLnRzIiwibmc6Ly9tYXQtY29udGVudGVkaXRhYmxlL2xpYi92YWxpZGF0b3JzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIERpcmVjdGl2ZSxcbiAgRWxlbWVudFJlZixcbiAgUmVuZGVyZXIyLFxuICBIb3N0TGlzdGVuZXIsXG4gIElucHV0LFxuICBIb3N0QmluZGluZyxcbiAgT3B0aW9uYWwsXG4gIFNlbGYsXG4gIERvQ2hlY2ssXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkQ29udHJvbCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIEZvcm1Hcm91cERpcmVjdGl2ZSwgTmdDb250cm9sLCBOZ0Zvcm0gfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBFcnJvclN0YXRlTWF0Y2hlciwgbWl4aW5FcnJvclN0YXRlLCBDYW5VcGRhdGVFcnJvclN0YXRlQ3RvciwgQ2FuVXBkYXRlRXJyb3JTdGF0ZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NvcmUnO1xuaW1wb3J0IHsgY29lcmNlQm9vbGVhblByb3BlcnR5IH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvZXJjaW9uJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcblxuLy8gQm9pbGVycGxhdGUgZm9yIGFwcGx5aW5nIG1peGlucyB0byBNYXRJbnB1dC5cbi8qKiBAZG9jcy1wcml2YXRlICovXG5jbGFzcyBNYXRJbnB1dEJhc2Uge1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgX2RlZmF1bHRFcnJvclN0YXRlTWF0Y2hlcjogRXJyb3JTdGF0ZU1hdGNoZXIsXG4gICAgICAgICAgICAgIHB1YmxpYyBfcGFyZW50Rm9ybTogTmdGb3JtLFxuICAgICAgICAgICAgICBwdWJsaWMgX3BhcmVudEZvcm1Hcm91cDogRm9ybUdyb3VwRGlyZWN0aXZlLFxuICAgICAgICAgICAgICAvKiogQGRvY3MtcHJpdmF0ZSAqL1xuICAgICAgICAgICAgICBwdWJsaWMgbmdDb250cm9sOiBOZ0NvbnRyb2wpIHt9XG59XG5leHBvcnQgY29uc3QgX01hdElucHV0TWl4aW5CYXNlOiBDYW5VcGRhdGVFcnJvclN0YXRlQ3RvciAmIHR5cGVvZiBNYXRJbnB1dEJhc2UgPVxuICBtaXhpbkVycm9yU3RhdGUoTWF0SW5wdXRCYXNlKTtcblxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbY29udGVudGVkaXRhYmxlXScsXG4gIHByb3ZpZGVyczogW1xuICAgIHsgcHJvdmlkZTogTWF0Rm9ybUZpZWxkQ29udHJvbCwgdXNlRXhpc3Rpbmc6IE1hdENvbnRlbnRlZGl0YWJsZURpcmVjdGl2ZSB9LFxuICBdXG59KVxuZXhwb3J0IGNsYXNzIE1hdENvbnRlbnRlZGl0YWJsZURpcmVjdGl2ZSBleHRlbmRzIF9NYXRJbnB1dE1peGluQmFzZVxuICBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBNYXRGb3JtRmllbGRDb250cm9sPHN0cmluZz4sIERvQ2hlY2ssIENhblVwZGF0ZUVycm9yU3RhdGUge1xuXG4gIC8qKlxuICAgKiBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIE1hdEZvcm1GaWVsZENvbnRyb2wuXG4gICAqIFNlZSBodHRwczovL21hdGVyaWFsLmFuZ3VsYXIuaW8vZ3VpZGUvY3JlYXRpbmctYS1jdXN0b20tZm9ybS1maWVsZC1jb250cm9sXG4gICAqL1xuICBzdGF0aWMgbmV4dElkID0gMDtcblxuICBASW5wdXQoKVxuICBnZXQgdmFsdWUoKTogc3RyaW5nIHsgcmV0dXJuIHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50W3RoaXMucHJvcFZhbHVlQWNjZXNzb3JdOyB9XG4gIHNldCB2YWx1ZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgaWYgKHZhbHVlICE9PSB0aGlzLnZhbHVlKSB7XG4gICAgICB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudFt0aGlzLnByb3BWYWx1ZUFjY2Vzc29yXSA9IHZhbHVlO1xuICAgICAgdGhpcy5zdGF0ZUNoYW5nZXMubmV4dCgpO1xuICAgIH1cbiAgfVxuXG4gIHJlYWRvbmx5IHN0YXRlQ2hhbmdlczogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgQEhvc3RCaW5kaW5nKCkgaWQgPSBgbWF0LWlucHV0LSR7TWF0Q29udGVudGVkaXRhYmxlRGlyZWN0aXZlLm5leHRJZCsrfWA7XG5cbiAgQElucHV0KClcbiAgZ2V0IHBsYWNlaG9sZGVyKCkge1xuICAgIHJldHVybiB0aGlzLl9wbGFjZWhvbGRlcjtcbiAgfVxuICBzZXQgcGxhY2Vob2xkZXIocGxoKSB7XG4gICAgdGhpcy5fcGxhY2Vob2xkZXIgPSBwbGg7XG4gICAgdGhpcy5zdGF0ZUNoYW5nZXMubmV4dCgpO1xuICB9XG4gIHByaXZhdGUgX3BsYWNlaG9sZGVyOiBzdHJpbmc7XG5cbiAgZm9jdXNlZCA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIGNvbnRlbnRFbXB0eTogQXJyYXk8c3RyaW5nPiA9IFsnPGJyPicsICc8ZGl2Pjxicj48L2Rpdj4nXTtcbiAgZ2V0IGVtcHR5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhdGhpcy52YWx1ZSB8fCB0aGlzLmNvbnRlbnRFbXB0eS5pbmNsdWRlcyh0aGlzLnZhbHVlKTtcbiAgfVxuXG4gIGdldCBzaG91bGRMYWJlbEZsb2F0KCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5mb2N1c2VkIHx8ICF0aGlzLmVtcHR5OyB9XG5cbiAgQElucHV0KClcbiAgZ2V0IHJlcXVpcmVkKCkge1xuICAgIHJldHVybiB0aGlzLl9yZXF1aXJlZDtcbiAgfVxuICBzZXQgcmVxdWlyZWQocmVxKSB7XG4gICAgdGhpcy5fcmVxdWlyZWQgPSBjb2VyY2VCb29sZWFuUHJvcGVydHkocmVxKTtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XG4gIH1cbiAgcHJpdmF0ZSBfcmVxdWlyZWQgPSBmYWxzZTtcblxuICBASW5wdXQoKVxuICBnZXQgZGlzYWJsZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2Rpc2FibGVkO1xuICB9XG4gIHNldCBkaXNhYmxlZChkaXMpIHtcbiAgICB0aGlzLl9kaXNhYmxlZCA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eShkaXMpO1xuICAgIHRoaXMuc3RhdGVDaGFuZ2VzLm5leHQoKTtcbiAgfVxuICBwcml2YXRlIF9kaXNhYmxlZCA9IGZhbHNlO1xuXG4gIEBIb3N0QmluZGluZygnYXR0ci5hcmlhLWludmFsaWQnKSBlcnJvclN0YXRlOiBib29sZWFuO1xuICBASW5wdXQoKSBlcnJvclN0YXRlTWF0Y2hlcjogRXJyb3JTdGF0ZU1hdGNoZXI7XG5cbiAgY29udHJvbFR5cGUgPSAnbWF0LWlucHV0JztcblxuICBASG9zdEJpbmRpbmcoJ2F0dHIuYXJpYS1kZXNjcmliZWRieScpIGRlc2NyaWJlZEJ5ID0gJyc7XG5cblxuICAvLyBQYXJ0IG9mIENvbnRyb2xWYWx1ZUFjY2Vzc29yXG4gIHByaXZhdGUgb25DaGFuZ2U6ICh2YWx1ZTogc3RyaW5nKSA9PiB2b2lkO1xuICBwcml2YXRlIG9uVG91Y2hlZDogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZW1vdmVEaXNhYmxlZFN0YXRlOiAoKSA9PiB2b2lkO1xuXG4gIEBJbnB1dCgpIHByb3BWYWx1ZUFjY2Vzc29yID0gJ2lubmVySFRNTCc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBlbGVtZW50UmVmOiBFbGVtZW50UmVmLFxuICAgIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMixcbiAgICBAT3B0aW9uYWwoKSBAU2VsZigpIHB1YmxpYyBuZ0NvbnRyb2w6IE5nQ29udHJvbCxcbiAgICBAT3B0aW9uYWwoKSBfcGFyZW50Rm9ybTogTmdGb3JtLFxuICAgIEBPcHRpb25hbCgpIF9wYXJlbnRGb3JtR3JvdXA6IEZvcm1Hcm91cERpcmVjdGl2ZSxcbiAgICBfZGVmYXVsdEVycm9yU3RhdGVNYXRjaGVyOiBFcnJvclN0YXRlTWF0Y2hlcixcbiAgKSB7XG4gICAgc3VwZXIoX2RlZmF1bHRFcnJvclN0YXRlTWF0Y2hlciwgX3BhcmVudEZvcm0sIF9wYXJlbnRGb3JtR3JvdXAsIG5nQ29udHJvbCk7XG4gICAgLy8gU2V0dGluZyB0aGUgdmFsdWUgYWNjZXNzb3IgZGlyZWN0bHkgKGluc3RlYWQgb2YgdXNpbmdcbiAgICAvLyB0aGUgcHJvdmlkZXJzKSB0byBhdm9pZCBydW5uaW5nIGludG8gYSBjaXJjdWxhciBpbXBvcnQuXG4gICAgaWYgKHRoaXMubmdDb250cm9sICE9IG51bGwpIHsgdGhpcy5uZ0NvbnRyb2wudmFsdWVBY2Nlc3NvciA9IHRoaXM7IH1cbiAgfVxuXG4gIG5nRG9DaGVjaygpIHtcbiAgICBpZiAodGhpcy5uZ0NvbnRyb2wpIHtcbiAgICAgIC8vIFdlIG5lZWQgdG8gcmUtZXZhbHVhdGUgdGhpcyBvbiBldmVyeSBjaGFuZ2UgZGV0ZWN0aW9uIGN5Y2xlLCBiZWNhdXNlIHRoZXJlIGFyZSBzb21lXG4gICAgICAvLyBlcnJvciB0cmlnZ2VycyB0aGF0IHdlIGNhbid0IHN1YnNjcmliZSB0byAoZS5nLiBwYXJlbnQgZm9ybSBzdWJtaXNzaW9ucykuIFRoaXMgbWVhbnNcbiAgICAgIC8vIHRoYXQgd2hhdGV2ZXIgbG9naWMgaXMgaW4gaGVyZSBoYXMgdG8gYmUgc3VwZXIgbGVhbiBvciB3ZSByaXNrIGRlc3Ryb3lpbmcgdGhlIHBlcmZvcm1hbmNlLlxuICAgICAgdGhpcy51cGRhdGVFcnJvclN0YXRlKCk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignaW5wdXQnKVxuICBjYWxsT25DaGFuZ2UoKSB7XG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uQ2hhbmdlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLm9uQ2hhbmdlKHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50W3RoaXMucHJvcFZhbHVlQWNjZXNzb3JdKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdmb2N1cycpXG4gIGNhbGxPbkZvY3VzZWQoKSB7XG4gICAgaWYgKHRoaXMuZm9jdXNlZCAhPT0gdHJ1ZSkge1xuICAgICAgdGhpcy5mb2N1c2VkID0gdHJ1ZTtcbiAgICAgIHRoaXMuc3RhdGVDaGFuZ2VzLm5leHQoKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdibHVyJylcbiAgY2FsbE9uVG91Y2hlZCgpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMub25Ub3VjaGVkID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLm9uVG91Y2hlZCgpO1xuICAgIH1cbiAgICBpZiAodGhpcy5mb2N1c2VkICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5mb2N1c2VkID0gZmFsc2U7XG4gICAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XG4gICAgfVxuICB9XG5cbiAgc2V0RGVzY3JpYmVkQnlJZHMoaWRzOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuZGVzY3JpYmVkQnkgPSBpZHMuam9pbignICcpO1xuICB9XG5cbiAgb25Db250YWluZXJDbGljaygpIHsgdGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTsgfVxuXG4gIC8qKlxuICAgKiBXcml0ZXMgYSBuZXcgdmFsdWUgdG8gdGhlIGVsZW1lbnQuXG4gICAqIFRoaXMgbWV0aG9kIHdpbGwgYmUgY2FsbGVkIGJ5IHRoZSBmb3JtcyBBUEkgdG8gd3JpdGVcbiAgICogdG8gdGhlIHZpZXcgd2hlbiBwcm9ncmFtbWF0aWMgKG1vZGVsIC0+IHZpZXcpIGNoYW5nZXMgYXJlIHJlcXVlc3RlZC5cbiAgICpcbiAgICogU2VlOiBbQ29udHJvbFZhbHVlQWNjZXNzb3JdKGh0dHBzOi8vYW5ndWxhci5pby9hcGkvZm9ybXMvQ29udHJvbFZhbHVlQWNjZXNzb3IjbWVtYmVycylcbiAgICovXG4gIHdyaXRlVmFsdWUodmFsdWU6IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRWYWx1ZSA9IHZhbHVlID09IG51bGwgPyAnJyA6IHZhbHVlO1xuICAgIHRoaXMucmVuZGVyZXIuc2V0UHJvcGVydHkodGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsIHRoaXMucHJvcFZhbHVlQWNjZXNzb3IsIG5vcm1hbGl6ZWRWYWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCBzaG91bGQgYmUgY2FsbGVkIHdoZW5cbiAgICogdGhlIGNvbnRyb2wncyB2YWx1ZSBjaGFuZ2VzIGluIHRoZSBVSS5cbiAgICpcbiAgICogVGhpcyBpcyBjYWxsZWQgYnkgdGhlIGZvcm1zIEFQSSBvbiBpbml0aWFsaXphdGlvbiBzbyBpdCBjYW4gdXBkYXRlXG4gICAqIHRoZSBmb3JtIG1vZGVsIHdoZW4gdmFsdWVzIHByb3BhZ2F0ZSBmcm9tIHRoZSB2aWV3ICh2aWV3IC0+IG1vZGVsKS5cbiAgICovXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXJzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCBzaG91bGQgYmUgY2FsbGVkIHdoZW4gdGhlIGNvbnRyb2wgcmVjZWl2ZXMgYSBibHVyIGV2ZW50LlxuICAgKiBUaGlzIGlzIGNhbGxlZCBieSB0aGUgZm9ybXMgQVBJIG9uIGluaXRpYWxpemF0aW9uIHNvIGl0IGNhbiB1cGRhdGUgdGhlIGZvcm0gbW9kZWwgb24gYmx1ci5cbiAgICovXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBieSB0aGUgZm9ybXMgQVBJIHdoZW4gdGhlIGNvbnRyb2wgc3RhdHVzIGNoYW5nZXMgdG8gb3IgZnJvbSBcIkRJU0FCTEVEXCIuXG4gICAqIERlcGVuZGluZyBvbiB0aGUgdmFsdWUsIGl0IHNob3VsZCBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYXBwcm9wcmlhdGUgRE9NIGVsZW1lbnQuXG4gICAqL1xuICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICBpZiAoaXNEaXNhYmxlZCkge1xuICAgICAgdGhpcy5yZW5kZXJlci5zZXRBdHRyaWJ1dGUodGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsICdkaXNhYmxlZCcsICd0cnVlJyk7XG4gICAgICB0aGlzLnJlbW92ZURpc2FibGVkU3RhdGUgPSB0aGlzLnJlbmRlcmVyLmxpc3Rlbih0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCwgJ2tleWRvd24nLCB0aGlzLmxpc3RlbmVyRGlzYWJsZWRTdGF0ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLnJlbW92ZURpc2FibGVkU3RhdGUpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW1vdmVBdHRyaWJ1dGUodGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQsICdkaXNhYmxlZCcpO1xuICAgICAgICB0aGlzLnJlbW92ZURpc2FibGVkU3RhdGUoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGxpc3RlbmVyRGlzYWJsZWRTdGF0ZShlOiBLZXlib2FyZEV2ZW50KSB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBEaXJlY3RpdmUsIElucHV0LCBIb3N0QmluZGluZywgVmlld0NvbnRhaW5lclJlZiwgT25Jbml0LCBPcHRpb25hbCwgU2VsZiwgRG9DaGVjayB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkQ29udHJvbCwgRXJyb3JTdGF0ZU1hdGNoZXIsIENhblVwZGF0ZUVycm9yU3RhdGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbCc7XG4vLyBpbXBvcnQgeyBDS0VkaXRvckNvbXBvbmVudCB9IGZyb20gJ0Bja2VkaXRvci9ja2VkaXRvcjUtYW5ndWxhci8vY2tlZGl0b3IuY29tcG9uZW50JztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE5nQ29udHJvbCwgTmdGb3JtLCBGb3JtR3JvdXBEaXJlY3RpdmUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBfTWF0SW5wdXRNaXhpbkJhc2UgfSBmcm9tICcuL21hdC1jb250ZW50ZWRpdGFibGUuZGlyZWN0aXZlJztcblxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbbWF0Q2tlZGl0b3JdJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgeyBwcm92aWRlOiBNYXRGb3JtRmllbGRDb250cm9sLCB1c2VFeGlzdGluZzogTWF0Q2tlZGl0b3JEaXJlY3RpdmUgfSxcbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBNYXRDa2VkaXRvckRpcmVjdGl2ZSAgZXh0ZW5kcyBfTWF0SW5wdXRNaXhpbkJhc2VcbiAgaW1wbGVtZW50cyBNYXRGb3JtRmllbGRDb250cm9sPHN0cmluZz4sIERvQ2hlY2ssIENhblVwZGF0ZUVycm9yU3RhdGUgLCBPbkluaXQge1xuXG4gIC8qKlxuICAgKiBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIE1hdEZvcm1GaWVsZENvbnRyb2wuXG4gICAqIFNlZSBodHRwczovL21hdGVyaWFsLmFuZ3VsYXIuaW8vZ3VpZGUvY3JlYXRpbmctYS1jdXN0b20tZm9ybS1maWVsZC1jb250cm9sXG4gICAqL1xuICBzdGF0aWMgbmV4dElkID0gMDtcblxuICBASW5wdXQoKVxuICBnZXQgdmFsdWUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gISF0aGlzLmVkaXRvci5lZGl0b3JJbnN0YW5jZSAmJiB0aGlzLmVkaXRvci5lZGl0b3JJbnN0YW5jZS5nZXREYXRhKCk7XG4gIH1cbiAgc2V0IHZhbHVlKHZhbHVlOiBzdHJpbmcpIHtcbiAgICBpZiAodmFsdWUgIT09IHRoaXMudmFsdWUpIHtcbiAgICAgIHRoaXMuZWRpdG9yLmRhdGEgPSB2YWx1ZTtcbiAgICAgIHRoaXMuc3RhdGVDaGFuZ2VzLm5leHQoKTtcbiAgICB9XG4gIH1cblxuICByZWFkb25seSBzdGF0ZUNoYW5nZXM6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIEBIb3N0QmluZGluZygpIGlkID0gYG1hdC1pbnB1dC0ke01hdENrZWRpdG9yRGlyZWN0aXZlLm5leHRJZCsrfWA7XG5cbiAgLy8gTmVlZCBzdXBwb3J0IGZyb20gQ2tlZGl0b3JcbiAgQElucHV0KCkgcGxhY2Vob2xkZXIgPSAnJztcblxuICBASW5wdXQoKSBjb250ZW50RW1wdHk6IHN0cmluZ1tdID0gWyc8YnI+JywgJzxwPiZuYnNwOzwvcD4nXTtcbiAgZ2V0IGVtcHR5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhdGhpcy52YWx1ZSB8fCB0aGlzLmNvbnRlbnRFbXB0eS5pbmNsdWRlcyh0aGlzLnZhbHVlKTtcbiAgfVxuXG4gIGdldCBzaG91bGRMYWJlbEZsb2F0KCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5mb2N1c2VkIHx8ICF0aGlzLmVtcHR5OyB9XG5cbiAgZm9jdXNlZCA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIHJlcXVpcmVkID0gZmFsc2U7XG5cbiAgQElucHV0KClcbiAgc2V0IGRpc2FibGVkKGlzRGlzYWJsZWQ6IGJvb2xlYW4pIHtcbiAgICB0aGlzLmVkaXRvci5zZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQpO1xuICAgIHRoaXMuc3RhdGVDaGFuZ2VzLm5leHQoKTtcbiAgfVxuICBnZXQgZGlzYWJsZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuZWRpdG9yLmRpc2FibGVkO1xuICB9XG5cbiAgQEhvc3RCaW5kaW5nKCdhdHRyLmFyaWEtaW52YWxpZCcpIGVycm9yU3RhdGU6IGJvb2xlYW47XG4gIEBJbnB1dCgpIGVycm9yU3RhdGVNYXRjaGVyOiBFcnJvclN0YXRlTWF0Y2hlcjtcblxuICBjb250cm9sVHlwZSA9ICdtYXQtaW5wdXQnO1xuXG4gIEBIb3N0QmluZGluZygnYXR0ci5hcmlhLWRlc2NyaWJlZGJ5JykgZGVzY3JpYmVkQnkgPSAnJztcblxuICBwcm90ZWN0ZWQgZWRpdG9yO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIC8vIEBIb3N0KCkgQFNlbGYoKSBAT3B0aW9uYWwoKSBwdWJsaWMgZWRpdG9yOiBDS0VkaXRvckNvbXBvbmVudCxcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmlld1JlZjogVmlld0NvbnRhaW5lclJlZixcbiAgICBAT3B0aW9uYWwoKSBAU2VsZigpIHB1YmxpYyBuZ0NvbnRyb2w6IE5nQ29udHJvbCxcbiAgICBAT3B0aW9uYWwoKSBfcGFyZW50Rm9ybTogTmdGb3JtLFxuICAgIEBPcHRpb25hbCgpIF9wYXJlbnRGb3JtR3JvdXA6IEZvcm1Hcm91cERpcmVjdGl2ZSxcbiAgICBfZGVmYXVsdEVycm9yU3RhdGVNYXRjaGVyOiBFcnJvclN0YXRlTWF0Y2hlcixcbiAgKSB7XG4gICAgc3VwZXIoX2RlZmF1bHRFcnJvclN0YXRlTWF0Y2hlciwgX3BhcmVudEZvcm0sIF9wYXJlbnRGb3JtR3JvdXAsIG5nQ29udHJvbCk7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICAvLyBDYW4ndCB1c2UgaW5qZWN0aW9uIHRvIGdldCBjb21wb25lbnQgcmVmZXJlbmNlXG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9pc3N1ZXMvODI3N1xuICAgIHRoaXMuZWRpdG9yID0gdGhpcy52aWV3UmVmWydfZGF0YSddLmNvbXBvbmVudFZpZXcuY29tcG9uZW50O1xuICAgIHRoaXMuZWRpdG9yLmJsdXIuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuZm9jdXNlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5zdGF0ZUNoYW5nZXMubmV4dCgpO1xuICAgIH0pO1xuICAgIHRoaXMuZWRpdG9yLmZvY3VzLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLmZvY3VzZWQgPSB0cnVlO1xuICAgICAgdGhpcy5zdGF0ZUNoYW5nZXMubmV4dCgpO1xuICAgIH0pO1xuICB9XG5cbiAgbmdEb0NoZWNrKCkge1xuICAgIGlmICh0aGlzLm5nQ29udHJvbCkge1xuICAgICAgLy8gV2UgbmVlZCB0byByZS1ldmFsdWF0ZSB0aGlzIG9uIGV2ZXJ5IGNoYW5nZSBkZXRlY3Rpb24gY3ljbGUsIGJlY2F1c2UgdGhlcmUgYXJlIHNvbWVcbiAgICAgIC8vIGVycm9yIHRyaWdnZXJzIHRoYXQgd2UgY2FuJ3Qgc3Vic2NyaWJlIHRvIChlLmcuIHBhcmVudCBmb3JtIHN1Ym1pc3Npb25zKS4gVGhpcyBtZWFuc1xuICAgICAgLy8gdGhhdCB3aGF0ZXZlciBsb2dpYyBpcyBpbiBoZXJlIGhhcyB0byBiZSBzdXBlciBsZWFuIG9yIHdlIHJpc2sgZGVzdHJveWluZyB0aGUgcGVyZm9ybWFuY2UuXG4gICAgICB0aGlzLnVwZGF0ZUVycm9yU3RhdGUoKTtcbiAgICB9XG4gIH1cblxuICBzZXREZXNjcmliZWRCeUlkcyhpZHM6IHN0cmluZ1tdKSB7XG4gICAgdGhpcy5kZXNjcmliZWRCeSA9IGlkcy5qb2luKCcgJyk7XG4gIH1cblxuICBvbkNvbnRhaW5lckNsaWNrKCkge1xuICAgIGlmICh0aGlzLmVkaXRvci5lZGl0b3JJbnN0YW5jZSkge1xuICAgICAgdGhpcy5lZGl0b3IuZWRpdG9ySW5zdGFuY2UuZWRpdGluZy52aWV3LmZvY3VzKCk7XG4gICAgICB0aGlzLnN0YXRlQ2hhbmdlcy5uZXh0KCk7XG4gICAgfVxuICB9XG5cbn1cbiIsImltcG9ydCB7IERpcmVjdGl2ZSwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE1hdEZvcm1GaWVsZENvbnRyb2wgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcblxuaW1wb3J0IHsgTWF0Q2tlZGl0b3JEaXJlY3RpdmUgfSBmcm9tICcuL21hdC1ja2VkaXRvci5kaXJlY3RpdmUnO1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbbWF0Q2tlZGl0b3JCYWxsb29uXScsXG4gIHByb3ZpZGVyczogW1xuICAgIHsgcHJvdmlkZTogTWF0Rm9ybUZpZWxkQ29udHJvbCwgdXNlRXhpc3Rpbmc6IE1hdENrZWRpdG9yQmFsbG9vbkRpcmVjdGl2ZSB9LFxuICBdXG59KVxuZXhwb3J0IGNsYXNzIE1hdENrZWRpdG9yQmFsbG9vbkRpcmVjdGl2ZSBleHRlbmRzIE1hdENrZWRpdG9yRGlyZWN0aXZlIHtcblxuICBASW5wdXQoKVxuICBzZXQgdG9vbGJhcihzaG93OiBib29sZWFuKSB7XG4gICAgaWYgKHRoaXMuZWRpdG9yICYmIHNob3cgIT09IHRoaXMudG9vbGJhck9wZW4pIHtcbiAgICAgIGNvbnN0IGJhbGxvb24gPSB0aGlzLmVkaXRvci5lZGl0b3JJbnN0YW5jZS5wbHVnaW5zLmdldCgnQmFsbG9vblRvb2xiYXInKTtcbiAgICAgIGlmIChzaG93KSB7XG4gICAgICAgIHRoaXMuc2hvd1Rvb2xiYXIoYmFsbG9vbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBiYWxsb29uLmhpZGUoKTtcbiAgICAgICAgdGhpcy50b29sYmFyT3BlbiA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBwcml2YXRlIHRvb2xiYXJPcGVuOiBib29sZWFuO1xuXG4gIG5nT25Jbml0KCkge1xuICAgIHN1cGVyLm5nT25Jbml0KCk7XG4gICAgdGhpcy5lZGl0b3IucmVhZHkuc3Vic2NyaWJlKGVkaXRvciA9PiB7XG4gICAgICBjb25zdCBiYWxsb29uID0gZWRpdG9yLnBsdWdpbnMuZ2V0KCdCYWxsb29uVG9vbGJhcicpO1xuICAgICAgYmFsbG9vbi5zdG9wTGlzdGVuaW5nKGVkaXRvci5tb2RlbC5kb2N1bWVudC5zZWxlY3Rpb24sICdjaGFuZ2U6cmFuZ2UnKTtcbiAgICAgIGJhbGxvb24uc3RvcExpc3RlbmluZyhiYWxsb29uLCAnX3NlbGVjdGlvbkNoYW5nZURlYm91bmNlZCcpO1xuICAgIH0pO1xuICAgIHRoaXMuZWRpdG9yLmZvY3VzLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICBpZiAodGhpcy50b29sYmFyT3Blbikge1xuICAgICAgICBjb25zdCBiYWxsb29uID0gdGhpcy5lZGl0b3IuZWRpdG9ySW5zdGFuY2UucGx1Z2lucy5nZXQoJ0JhbGxvb25Ub29sYmFyJyk7XG4gICAgICAgIHRoaXMuc2hvd1Rvb2xiYXIoYmFsbG9vbik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHNob3dUb29sYmFyKGJhbGxvb24pIHtcbiAgICBpZiAoIWJhbGxvb24uX2JhbGxvb24uaGFzVmlldyhiYWxsb29uLnRvb2xiYXJWaWV3KSkge1xuICAgICAgYmFsbG9vbi5saXN0ZW5Ubyh0aGlzLmVkaXRvci5lZGl0b3JJbnN0YW5jZS51aSwgJ3VwZGF0ZScsICgpID0+IHtcbiAgICAgICAgYmFsbG9vbi5fYmFsbG9vbi51cGRhdGVQb3NpdGlvbihiYWxsb29uLl9n