mat-contenteditable
Version:
Angular contenteditable directive for Angular forms and Material Design
1,019 lines (1,004 loc) • 92.7 kB
JavaScript
(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> </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