UNPKG

@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
/**----------------------------------------------------------------------------------------- * 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 }] } });