mat-contenteditable
Version:
Angular contenteditable directive for Angular forms and Material Design
996 lines (986 loc) • 71.6 kB
JavaScript
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> </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