@progress/kendo-angular-dropdowns
Version:
A wide variety of native Angular dropdown components including AutoComplete, ComboBox, DropDownList, DropDownTree, MultiColumnComboBox, MultiSelect, and MultiSelectTree
385 lines (384 loc) • 15.1 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { Component, Renderer2, Input, Output, EventEmitter, ElementRef, HostBinding, Injector, NgZone } from '@angular/core';
import { isDocumentAvailable, isObjectPresent, isSafari, removeHTMLAttributes, setHTMLAttributes, Keys, parseAttributes, EventsOutsideAngularDirective } from '@progress/kendo-angular-common';
import { combineStr, isJapanese } from './util';
import { LocalizationService } from '@progress/kendo-angular-l10n';
import { Subscription } from 'rxjs';
import { NgControl } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "@progress/kendo-angular-l10n";
/**
* @hidden
*/
export class SearchBarComponent {
localization;
injector;
input;
ngZone;
direction;
tagListId;
set readonly(readonly) {
this._readonly = readonly;
if (this._readonly) {
this.renderer.setAttribute(this.input.nativeElement, 'readonly', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'readonly');
}
}
get readonly() {
return this._readonly;
}
set disabled(disabled) {
this._disabled = disabled;
if (this._disabled) {
this.renderer.setAttribute(this.input.nativeElement, 'disabled', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'disabled');
}
}
get disabled() {
return this._disabled;
}
set isRequired(isRequired) {
this._isRequired = isRequired;
if (this._isRequired) {
this.renderer.setAttribute(this.input.nativeElement, 'required', '');
}
else {
this.renderer.removeAttribute(this.input.nativeElement, 'required');
}
}
get isRequired() {
return this._isRequired;
}
set isSuggestable(isSuggestable) {
this._isSuggestable = isSuggestable;
this.setAriaAutocomplete();
}
get isSuggestable() {
return this._isSuggestable;
}
set isFilterable(isFilterable) {
this._isFilterable = isFilterable;
this.setAriaAutocomplete();
}
get isFilterable() {
return this._isFilterable;
}
get userInput() {
return this._userInput;
}
set userInput(userInput) {
this._userInput = userInput || "";
}
/**
* @hidden
*/
get formControl() {
const ngControl = this.injector.get(NgControl, null);
return ngControl?.control || null;
}
suggestedText;
/**
* @hidden
*/
set inputAttributes(attributes) {
if (isObjectPresent(this.parsedAttributes)) {
removeHTMLAttributes(this.parsedAttributes, this.renderer, this.input.nativeElement);
}
this._inputAttributes = attributes;
this.parsedAttributes = this.inputAttributes ?
parseAttributes(this.inputAttributes, this.defaultAttributes) :
this.inputAttributes;
this.setInputAttributes();
}
get inputAttributes() {
return this._inputAttributes;
}
id;
activeDescendant;
tabIndex;
isLoading;
ariaControls;
ariaExpanded = null;
get attrAriaInvalid() {
return this.formControl?.invalid ? true : null;
}
set placeholder(text) {
this._placeholder = text || '';
this.setInputSize();
}
get placeholder() {
return this._placeholder;
}
role = 'combobox';
get dir() {
return this.direction;
}
valueChange = new EventEmitter();
onBlur = new EventEmitter();
onFocus = new EventEmitter();
onClick = new EventEmitter();
onNavigate = new EventEmitter();
get value() {
return this.input.nativeElement.value;
}
_isRequired;
_readonly;
_disabled;
_userInput = "";
_previousValue = "";
_placeholder = "";
_isSuggestable = false;
_isFilterable = false;
renderer;
subs = new Subscription();
_inputAttributes;
parsedAttributes = {};
get defaultAttributes() {
return {
id: this.id,
disabled: this.disabled ? '' : null,
readonly: this.readonly ? '' : null,
placeholder: this.placeholder,
tabIndex: this.tabIndex,
tabindex: this.tabIndex,
dir: this.direction,
required: this.isRequired ? '' : null,
'aria-haspopup': 'listbox',
'aria-expanded': this.ariaExpanded,
'aria-controls': this.ariaControls,
'aria-activedescendant': this.activeDescendant,
'aria-busy': this.isLoading,
'aria-invalid': this.formControl?.invalid
};
}
get mutableAttributes() {
return {
autocomplete: 'off',
role: this.role,
'aria-describedby': this.tagListId
};
}
constructor(localization, renderer, injector, input, ngZone) {
this.localization = localization;
this.injector = injector;
this.input = input;
this.ngZone = ngZone;
this.direction = localization.rtl ? 'rtl' : 'ltr';
this.renderer = renderer;
this.renderer.addClass(this.input.nativeElement, 'k-input-inner');
this.renderer.setAttribute(this.input.nativeElement, 'aria-haspopup', 'listbox');
this.renderer.setAttribute(this.input.nativeElement, 'autocomplete', 'off');
}
ngOnInit() {
this.subs.add(this.localization
.changes.subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr'));
}
ngOnChanges(changes) {
if (!isDocumentAvailable()) {
return;
}
let previousUserInput;
if (this.input && (changes.userInput || changes.suggestedText)) {
if (changes.userInput && changes.userInput.previousValue) {
if (this._previousValue === changes.userInput.previousValue) {
previousUserInput = this._previousValue;
}
else {
previousUserInput = changes.userInput.currentValue || "";
}
}
else {
previousUserInput = this._previousValue;
}
const caretStart = this.input.nativeElement.selectionStart;
const caretAtEnd = previousUserInput.length === caretStart;
this.writeInputValue(this.suggestedText ? combineStr(this.userInput, this.suggestedText) : this.userInput);
if (this.suggestedText) {
this.setInputSelection(this.userInput.length, this.suggestedText.length);
}
else if (isSafari(navigator.userAgent) && !caretAtEnd) {
this.setInputSelection(caretStart, this.userInput.length);
}
else if (caretAtEnd) {
this.setInputSelection(this.userInput.length, this.userInput.length);
}
else {
this.setInputSelection(caretStart, caretStart);
}
this._previousValue = this.userInput;
}
}
ngAfterViewInit() {
this.subs.add(this.input.nativeElement.addEventListener('input', (event) => this.handleInput(event)));
this.subs.add(this.input.nativeElement.addEventListener('focus', (event) => this.handleFocus(event)));
this.subs.add(this.input.nativeElement.addEventListener('blur', (event) => this.handleBlur(event)));
this.subs.add(this.input.nativeElement.addEventListener('keydown', (event) => this.handleKeydown(event)));
}
ngOnDestroy() {
this.subs.unsubscribe();
}
writeInputValue(text) {
if (isDocumentAvailable()) {
this.renderer.setProperty(this.input.nativeElement, 'value', text);
}
}
setInputSelection(start, end) {
if (isDocumentAvailable() && this.input.nativeElement === document.activeElement) {
try {
this.input.nativeElement.setSelectionRange(start, end);
}
catch (e) {
//Make sure that the element is in the DOM before you invoke its methods
}
}
}
setAriaAutocomplete() {
if (this.isFilterable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'list');
}
if (this.isSuggestable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'inline');
}
if (this.isFilterable && this.isSuggestable) {
this.renderer.setAttribute(this.input.nativeElement, 'aria-autocomplete', 'both');
}
if (!this.isFilterable && !this.isSuggestable) {
this.renderer.removeAttribute(this.input.nativeElement, 'aria-autocomplete');
}
}
handleInput(event) {
const target = event.target;
const isBrowserSafari = isSafari(navigator.userAgent);
const value = isBrowserSafari && isJapanese(target.value) ? event.data : target.value;
if (value !== this.userInput) {
this._previousValue = value;
this.valueChange.emit(value);
}
}
handleFocus(event) {
this.onFocus.emit(event);
}
handleBlur(event) {
this.onBlur.emit(event);
}
handleKeydown(event) {
const keyCode = event.keyCode;
const keys = [Keys.ArrowUp, Keys.ArrowDown, Keys.ArrowLeft, Keys.ArrowRight, Keys.Enter,
Keys.Escape, Keys.Delete, Keys.Backspace, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp];
if (keys.indexOf(keyCode) > -1) {
this.onNavigate.emit(event);
}
}
focus() {
if (isDocumentAvailable()) {
this.input.nativeElement.focus();
}
}
blur() {
if (isDocumentAvailable()) {
this.input.nativeElement.blur();
}
}
setInputSize() {
const lengthOf = x => x ? x.length : 0;
const input = this.input.nativeElement;
const placeholderLength = lengthOf(this.placeholder);
const textLength = lengthOf(this.value);
const size = Math.max(placeholderLength, textLength, 1);
this.renderer.setAttribute(input, 'size', size.toString());
}
setInputAttributes() {
const attributesToRender = Object.assign({}, this.mutableAttributes, this.parsedAttributes);
setHTMLAttributes(attributesToRender, this.renderer, this.input.nativeElement, this.ngZone);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SearchBarComponent, deps: [{ token: i1.LocalizationService }, { token: i0.Renderer2 }, { token: i0.Injector }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SearchBarComponent, isStandalone: true, selector: "input[kendoSearchbar]", inputs: { tagListId: "tagListId", readonly: "readonly", disabled: "disabled", isRequired: "isRequired", isSuggestable: "isSuggestable", isFilterable: "isFilterable", userInput: "userInput", suggestedText: "suggestedText", inputAttributes: "inputAttributes", id: "id", activeDescendant: "activeDescendant", tabIndex: "tabIndex", isLoading: "isLoading", ariaControls: "ariaControls", ariaExpanded: "ariaExpanded", placeholder: "placeholder" }, outputs: { valueChange: "valueChange", onBlur: "onBlur", onFocus: "onFocus", onClick: "onClick", onNavigate: "onNavigate" }, host: { properties: { "attr.id": "this.id", "attr.aria-activedescendant": "this.activeDescendant", "attr.tabindex": "this.tabIndex", "attr.aria-busy": "this.isLoading", "attr.aria-controls": "this.ariaControls", "attr.aria-expanded": "this.ariaExpanded", "attr.aria-invalid": "this.attrAriaInvalid", "attr.placeholder": "this.placeholder", "attr.role": "this.role", "attr.dir": "this.dir" } }, usesOnChanges: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SearchBarComponent, decorators: [{
type: Component,
args: [{
selector: 'input[kendoSearchbar]',
template: ``,
standalone: true,
imports: [EventsOutsideAngularDirective]
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i0.Renderer2 }, { type: i0.Injector }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { tagListId: [{
type: Input
}], readonly: [{
type: Input
}], disabled: [{
type: Input
}], isRequired: [{
type: Input
}], isSuggestable: [{
type: Input
}], isFilterable: [{
type: Input
}], userInput: [{
type: Input
}], suggestedText: [{
type: Input
}], inputAttributes: [{
type: Input
}], id: [{
type: HostBinding,
args: ['attr.id']
}, {
type: Input
}], activeDescendant: [{
type: HostBinding,
args: ['attr.aria-activedescendant']
}, {
type: Input
}], tabIndex: [{
type: HostBinding,
args: ['attr.tabindex']
}, {
type: Input
}], isLoading: [{
type: HostBinding,
args: ['attr.aria-busy']
}, {
type: Input
}], ariaControls: [{
type: HostBinding,
args: ['attr.aria-controls']
}, {
type: Input
}], ariaExpanded: [{
type: HostBinding,
args: ['attr.aria-expanded']
}, {
type: Input
}], attrAriaInvalid: [{
type: HostBinding,
args: ['attr.aria-invalid']
}], placeholder: [{
type: HostBinding,
args: ['attr.placeholder']
}, {
type: Input
}], role: [{
type: HostBinding,
args: ['attr.role']
}], dir: [{
type: HostBinding,
args: ['attr.dir']
}], valueChange: [{
type: Output
}], onBlur: [{
type: Output
}], onFocus: [{
type: Output
}], onClick: [{
type: Output
}], onNavigate: [{
type: Output
}] } });