/*
* Copyright (C) 2022 Huawei Device Co., Ltd.
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BaseElement, element } from '../BaseElement';
import { selectHtmlStr } from './LitSelectHtml';
import { LitSelectOption } from './LitSelectOption';
import { SpSystemTrace } from '../../trace/component/SpSystemTrace';
@element('lit-select')
export class LitSelect extends BaseElement {
private focused: unknown;
private selectInputEl: unknown;
private selectSearchInputEl: HTMLInputElement | null | undefined;
private selectVInputEl: HTMLInputElement | null | undefined;
private selectOptions: HTMLDivElement | null | undefined;
private selectItem: string = '';
private selectClearEl: unknown;
private selectIconEl: unknown;
private bodyEl: unknown;
private selectSearchEl: unknown;
private selectMultipleRootEl: unknown;
private currentSelectedValue: string = '';
static get observedAttributes(): string[] {
return [
'value',
'default-value',
'placeholder',
'disabled',
'loading',
'allow-clear',
'show-search',
'list-height',
'border',
'mode',
'showSearchInput',
'tabSelect'
];
}
get value(): string {
return this.getAttribute('value') || this.defaultValue;
}
set value(selectValue) {
this.setAttribute('value', selectValue);
}
get rounded(): boolean {
return this.hasAttribute('rounded');
}
set rounded(selectRounded: boolean) {
if (selectRounded) {
this.setAttribute('rounded', '');
} else {
this.removeAttribute('rounded');
}
}
get placement(): string {
return this.getAttribute('placement') || '';
}
set placement(selectPlacement: string) {
if (selectPlacement) {
this.setAttribute('placement', selectPlacement);
} else {
this.removeAttribute('placement');
}
}
get border(): string {
return this.getAttribute('border') || 'true';
}
set border(selectBorder) {
if (selectBorder) {
this.setAttribute('border', 'true');
} else {
this.setAttribute('border', 'false');
}
}
get listHeight(): string {
return this.getAttribute('list-height') || '256px';
}
set listHeight(selectListHeight) {
this.setAttribute('list-height', selectListHeight);
}
get defaultPlaceholder(): string {
return this.getAttribute('placeholder') || '请选择';
}
set canInsert(can: boolean) {
if (can) {
this.setAttribute('canInsert', '');
} else {
this.removeAttribute('canInsert');
}
}
get canInsert(): boolean {
return this.hasAttribute('canInsert');
}
get showSearch(): boolean {
return this.hasAttribute('show-search');
}
get defaultValue(): string {
return this.getAttribute('default-value') || '';
}
set defaultValue(selectDefaultValue) {
this.setAttribute('default-value', selectDefaultValue);
}
get placeholder(): string {
return this.getAttribute('placeholder') || this.defaultPlaceholder;
}
set placeholder(selectPlaceHolder) {
this.setAttribute('placeholder', selectPlaceHolder);
}
get loading(): boolean {
return this.hasAttribute('loading');
}
set loading(selectLoading) {
if (selectLoading) {
this.setAttribute('loading', '');
} else {
this.removeAttribute('loading');
}
}
get showSearchInput(): boolean {
return this.hasAttribute('showSearchInput');
}
set showSearchInput(isHide: boolean) {
if (isHide) {
this.setAttribute('showSearchInput', '');
} else {
this.removeAttribute('showSearchInput');
}
}
set showItem(item: string) {
this.selectItem = item;
}
set dataSource(selectDataSource: unknown) {
this.innerHTML = ''; // @ts-ignore
if (selectDataSource.length > 0) {
// @ts-ignore
this.bodyEl!.style.display = 'flex';
this.querySelectorAll('lit-select-option').forEach((a) => {
this.removeChild(a);
});
let valuesSet = new Set();
let flag = true; // 假设所有 value 都是唯一的
// @ts-ignore
selectDataSource.forEach(item => {
if (valuesSet.has(item.value)) {
flag = false; // 如果value有重复,就设置flag为false
return;
}
valuesSet.add(item.value);
});
// @ts-ignore
selectDataSource.forEach((dateSourceBean: unknown) => {
if (dateSourceBean) {
let selectOption = document.createElement('lit-select-option');
let optionData = {
// @ts-ignore
value: dateSourceBean.value ? dateSourceBean.value : dateSourceBean.name || dateSourceBean, // @ts-ignore
name: dateSourceBean.name ? dateSourceBean.name : dateSourceBean,
};
if (!flag) { // 如果数组的value值不是唯一的,就用name做为value值,避免多个选项被选中
optionData = {
// @ts-ignore
value: dateSourceBean.name ? dateSourceBean.name : dateSourceBean, // @ts-ignore
name: dateSourceBean.name ? dateSourceBean.name : dateSourceBean,
};
}
selectOption.textContent = optionData.name;
selectOption.setAttribute('value', optionData.value);
if (this.currentSelectedValue === optionData.value) {
selectOption.setAttribute('selected', '');
}
// @ts-ignore
this.selectInputEl!.value = '';
this.append(selectOption);
}
});
this.initOptions();
} else {
// @ts-ignore
this.bodyEl!.style.display = 'none';
}
}
initElements(): void {
this.selectVInputEl = this.shadowRoot!.querySelector('#select-input') as HTMLInputElement;
this.selectVInputEl?.addEventListener('keyup', (e) => {
if (e.code === 'Enter' || e.code === 'NumpadEnter') {// @ts-ignore
this.selectVInputEl.blur();// @ts-ignore
this.selectInputEl.value = this.selectVInputEl.value;
}
});
if (this.showSearchInput) {
this.shadowRoot!.querySelector('.body-select')!.style.display = 'block';
this.selectSearchInputEl = this.shadowRoot!.querySelector('#search-input') as HTMLInputElement;
this.selectSearchInputEl?.addEventListener('keyup', (evt) => {
let options = [];
options = [...this.querySelectorAll('lit-select-option')];
options.filter((a: LitSelectOption) => {
if (a.textContent!.indexOf(this.selectSearchInputEl!.value) <= -1) {
a.style.display = 'none';
} else {
a.style.display = 'flex';
}
});
evt.preventDefault();
evt.stopPropagation();
});
}
}
initHtml(): string {
return `
${selectHtmlStr(this.listHeight)}
`;
}
isMultiple(): boolean {
return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple';
}
newTag(value: unknown, text: unknown): HTMLDivElement {
let tag: unknown = document.createElement('div');
let icon: unknown = document.createElement('lit-icon'); // @ts-ignore
icon.classList.add('tag-close'); // @ts-ignore
icon.name = 'close';
let span = document.createElement('span'); // @ts-ignore
tag.classList.add('tag'); // @ts-ignore
span.dataset.value = value; // @ts-ignore
span.textContent = text; // @ts-ignore
tag.append(span); // @ts-ignore
tag.append(icon); // @ts-ignore
icon.onclick = (ev: unknown): void => {
// @ts-ignore
tag.parentElement.removeChild(tag);
this.querySelector(`lit-select-option[value=${value}]`)!.removeAttribute('selected');
if (this.shadowRoot!.querySelectorAll('.tag').length === 0) {
// @ts-ignore
this.selectInputEl.style.width = 'auto'; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
} // @ts-ignore
ev.stopPropagation();
}; // @ts-ignore
tag.value = value; // @ts-ignore
tag.dataset.value = value; // @ts-ignore
tag.text = text; // @ts-ignore
tag.dataset.text = text; // @ts-ignore
return tag;
}
connectedCallback(): void {
this.tabIndex = 0;
this.focused = false;
this.bodyEl = this.shadowRoot!.querySelector('.body');
this.selectInputEl = this.shadowRoot!.querySelector('input');
this.selectClearEl = this.shadowRoot!.querySelector('.clear');
this.selectIconEl = this.shadowRoot!.querySelector('.icon');
this.selectSearchEl = this.shadowRoot!.querySelector('.search');
this.selectMultipleRootEl = this.shadowRoot!.querySelector('.multipleRoot');
this.selectOptions = this.shadowRoot!.querySelector('.body-opt') as HTMLDivElement;
this.setEventClick();
this.setEvent(); // @ts-ignore
this.selectInputEl.onblur = (ev: unknown): void => {
if (this.hasAttribute('disabled')) {
return;
}
if (this.isMultiple()) {
if (this.hasAttribute('show-search')) {
// @ts-ignore
this.selectSearchEl.style.display = 'none'; // @ts-ignore
this.selectIconEl.style.display = 'flex';
}
} else {
// @ts-ignore
if (this.selectInputEl.placeholder !== this.defaultPlaceholder) {
// @ts-ignore
this.selectInputEl.value = this.selectInputEl.placeholder; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
}
if (this.hasAttribute('show-search')) {
// @ts-ignore
this.selectSearchEl.style.display = 'none'; // @ts-ignore
this.selectIconEl.style.display = 'flex';
}
}
};
this.setOninput();
this.setOnkeydown();
}
setOninput(): void {
// @ts-ignore
this.selectInputEl.oninput = (ev: unknown): void => {
let els: Element[] = [...this.querySelectorAll('lit-select-option')];
if (this.hasAttribute('show-search')) {
// @ts-ignore
if (!ev.target.value) {
// @ts-ignore
els.forEach((a: unknown) => (a.style.display = 'flex'));
} else {
this.setSelectItem(els, ev);
}
} else {
// @ts-ignore
this.value = ev.target.value;
}
};
}
setSelectItem(els: Element[], ev: unknown): void {
els.forEach((a: unknown) => {
// @ts-ignore
let value = a.getAttribute('value');
if (
// @ts-ignore
value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 || // @ts-ignore
a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1
) {
// @ts-ignore
a.style.display = 'flex';
} else {
// @ts-ignore
a.style.display = 'none';
}
});
}
setEventClick(): void {
// @ts-ignore
this.selectClearEl.onclick = (ev: unknown): void => {
if (this.isMultiple()) {
let delNodes: Array = []; // @ts-ignore
this.selectMultipleRootEl.childNodes.forEach((a: unknown) => {
// @ts-ignore
if (a.tagName === 'DIV') {
delNodes.push(a);
}
});
for (let i = 0; i < delNodes.length; i++) {
// @ts-ignore
delNodes[i].remove();
}
if (this.shadowRoot!.querySelectorAll('.tag').length === 0) {
// @ts-ignore
this.selectInputEl.style.width = 'auto'; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
}
}
this.querySelectorAll('lit-select-option').forEach((a) => a.removeAttribute('selected')); // @ts-ignore
this.selectInputEl.value = ''; // @ts-ignore
this.selectClearEl.style.display = 'none'; // @ts-ignore
this.selectIconEl.style.display = 'flex';
this.blur(); // @ts-ignore
ev.stopPropagation();
this.dispatchEvent(new CustomEvent('onClear', { detail: ev }));
};
this.initOptions();
this.onclick = (ev: unknown): void => {
// @ts-ignore
if (ev.target.tagName === 'LIT-SELECT') {
if (this.focused === false) {
// @ts-ignore
this.selectInputEl.focus();
this.focused = true; // @ts-ignore
this.bodyEl!.style.display = 'flex';
} else {
this.focused = false;
}
}
};
}
setEvent(): void {
this.onmouseover = this.onfocus = (ev): void => {
if (this.focused === false && this.hasAttribute('adaptive-expansion')) {
// @ts-ignore
if (this.parentElement!.offsetTop < this.bodyEl!.clientHeight) {
// @ts-ignore
this.bodyEl!.classList.add('body-bottom');
} else {
// @ts-ignore
this.bodyEl!.classList.remove('body-bottom');
}
}
if (this.hasAttribute('allow-clear')) {
// @ts-ignore
if (this.selectInputEl.value.length > 0 || this.selectInputEl.placeholder !== this.defaultPlaceholder) {
// @ts-ignore
this.selectClearEl.style.display = 'flex'; // @ts-ignore
this.selectIconEl.style.display = 'none';
} else {
// @ts-ignore
this.selectClearEl.style.display = 'none'; // @ts-ignore
this.selectIconEl.style.display = 'flex';
}
}
};
this.onmouseout = this.onblur = (ev): void => {
if (this.hasAttribute('allow-clear')) {
// @ts-ignore
this.selectClearEl.style.display = 'none'; // @ts-ignore
this.selectIconEl.style.display = 'flex';
}
this.focused = false;
}; // @ts-ignore
this.selectInputEl.onfocus = (ev: unknown): void => {
if (this.hasAttribute('disabled')) {
return;
}
if (this.hasAttribute('show-search')) {
// @ts-ignore
this.selectSearchEl.style.display = 'flex'; // @ts-ignore
this.selectIconEl.style.display = 'none';
}
this.querySelectorAll('lit-select-option').forEach((a) => {
// @ts-ignore
a.style.display = 'flex';
});
};
}
setOnkeydown(): void {
// @ts-ignore
this.selectInputEl.onkeydown = (ev: KeyboardEvent): void => {
ev.stopPropagation();
if (this.hasAttribute('tabselect')) {
// @ts-ignore
this.selectInputEl.readOnly = true;
} else {
// @ts-ignore
if (ev.key === 'Backspace') {
if (this.isMultiple()) {
// @ts-ignore
let tag = this.selectMultipleRootEl.lastElementChild.previousElementSibling;
if (tag) {
this.querySelector(`lit-select-option[value=${tag.value}]`)?.removeAttribute('selected');
tag.remove();
if (this.shadowRoot!.querySelectorAll('.tag').length === 0) {
// @ts-ignore
this.selectInputEl.style.width = 'auto'; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
}
}
} else {
this.clear();
this.dispatchEvent(new CustomEvent('onClear', { detail: ev })); //向外派发清理事件
} // @ts-ignore
} else if (ev.key === 'Enter') {
if (!this.canInsert) {
let filter = [...this.querySelectorAll('lit-select-option')].filter(
// @ts-ignore
(a: unknown) => a.style.display !== 'none'
);
if (filter.length > 0) {
// @ts-ignore
this.selectInputEl.value = filter[0].textContent; // @ts-ignore
this.selectInputEl.placeholder = filter[0].textContent;
this.blur();
// @ts-ignore
this.value = filter[0].getAttribute('value');
this.dispatchEvent(
new CustomEvent('change', {
detail: {
selected: true,
value: filter[0].getAttribute('value'),
text: filter[0].textContent,
},
})
);
}
}// @ts-ignore
} else if (ev.key === '0' && ev.target.value.length === 1 && ev.target.value === '0') {
// @ts-ignore
ev.preventDefault();
}
}
};
}
initOptions(): void {
this.querySelectorAll('lit-select-option').forEach((a) => {
if (this.isMultiple()) {
a.setAttribute('check', '');
if (a.getAttribute('value') === this.defaultValue) {
let tag = this.newTag(a.getAttribute('value'), a.textContent); // @ts-ignore
this.selectMultipleRootEl.insertBefore(tag, this.selectInputEl); // @ts-ignore
this.selectInputEl.placeholder = ''; // @ts-ignore
this.selectInputEl.value = ''; // @ts-ignore
this.selectInputEl.style.width = '1px';
a.setAttribute('selected', '');
}
} else {
if (a.hasAttribute('selected')) {
a.removeAttribute('selected');
}
if (a.getAttribute('value') === this.defaultValue) {
// @ts-ignore
this.selectInputEl.value = a.textContent;
a.setAttribute('selected', '');
}
}
a.addEventListener('mouseup', (e) => {
e.stopPropagation();
});
a.addEventListener('mousedown', (e) => {
e.stopPropagation();
});
this.onSelectedEvent(a);
});
}
onSelectedEvent(a: Element): void {
a.addEventListener('onSelected', (e: unknown) => {
if (this.isMultiple()) {
if (a.hasAttribute('selected')) {
// @ts-ignore
let tag = this.shadowRoot!.querySelector(`div[data-value=${e.detail.value}]`) as HTMLElement;
if (tag) {
tag.parentElement!.removeChild(tag);
} // @ts-ignore
e.detail.selected = false;
} else {
// @ts-ignore
let tag = this.newTag(e.detail.value, e.detail.text); // @ts-ignore
this.selectMultipleRootEl.insertBefore(tag, this.selectInputEl); // @ts-ignore
this.selectInputEl.placeholder = ''; // @ts-ignore
this.selectInputEl.value = ''; // @ts-ignore
this.selectInputEl.style.width = '1px';
}
if (this.shadowRoot!.querySelectorAll('.tag').length === 0) {
// @ts-ignore
this.selectInputEl.style.width = 'auto'; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
} // @ts-ignore
this.selectInputEl.focus();
} else {
[...this.querySelectorAll('lit-select-option')].forEach((item) => {
if (item.hasAttribute('selected')) {
this.currentSelectedValue = item.getAttribute('value') || '';
}
item.removeAttribute('selected');
});
this.blur(); // @ts-ignore
this.bodyEl!.style.display = 'none';
// @ts-ignore
this.selectInputEl.value = e.detail.text;
}
if (a.getAttribute('value') === this.currentSelectedValue) {
a.removeAttribute('selected');
this.currentSelectedValue = '';
// @ts-ignore
this.selectInputEl.value = '';
// @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
} else {
this.currentSelectedValue = a.getAttribute('value') || '';
a.setAttribute('selected', '');
}
this.value = this.currentSelectedValue;
// @ts-ignore
this.dispatchEvent(new CustomEvent('change', { detail: { selectValue: this.currentSelectedValue, text: e.detail.text } })); //向外层派发change事件,返回当前选中项
});
}
clear(): void {
// @ts-ignore
this.selectInputEl.value = ''; // @ts-ignore
this.selectInputEl.placeholder = this.defaultPlaceholder;
}
reset(): void {
this.querySelectorAll('lit-select-option').forEach((a) => {
[...this.querySelectorAll('lit-select-option')].forEach((a) => a.removeAttribute('selected'));
if (a.getAttribute('value') === this.defaultValue) {
// @ts-ignore
this.selectInputEl.value = a.textContent;
a.setAttribute('selected', '');
}
});
}
disconnectedCallback(): void { }
adoptedCallback(): void { }
attributeChangedCallback(name: unknown, oldValue: unknown, newValue: unknown): void {
if (name === 'value' && this.selectInputEl) {
if (newValue) {
[...this.querySelectorAll('lit-select-option')].forEach((a) => {
if (a.getAttribute('value') === newValue) {
this.currentSelectedValue = a.getAttribute('value') || '';
a.setAttribute('selected', ''); // @ts-ignore
this.selectInputEl.value = a.textContent;
} else {
a.removeAttribute('selected');
}
});
} else {
this.clear();
}
}
}
}