cg-select/src/cg-selectTS.ts

389 lines
12 KiB
TypeScript
Raw Normal View History

2023-01-09 17:57:56 +03:00
import { ICreateBreadCrumb } from './components/create-element/create-element.interface';
2023-01-06 13:40:18 +03:00
import {
2023-01-09 17:57:56 +03:00
CreateBreadCrumb,
2023-01-06 13:40:18 +03:00
createNativeSelect,
createNativeSelectOption,
} from './components/create-element/create-elementTs';
2023-01-09 17:57:56 +03:00
import { IDataItem, ITextSelect } from './components/utils/urils.interface';
2023-01-09 17:57:56 +03:00
import {
createSelected,
getFormatItem,
getSelectText,
nativeOptionMultiple,
nativeOptionOrdinary,
} from './components/utils/utilsTs';
2023-01-09 17:57:56 +03:00
2023-01-06 14:57:14 +03:00
import { ICgSelect } from './interfaces/cg-select.interface';
2023-01-05 18:21:10 +03:00
import { IItems } from './interfaces/items.interface';
import './main.scss';
2023-01-06 14:57:14 +03:00
export class CGSelect implements ICgSelect {
2023-01-05 18:21:10 +03:00
selector: string;
selected?: string;
placeholder?: string;
items?: IItems[] | string[] | any;
darkTheme?: boolean;
searchMode?: boolean;
closeOnSelect?: boolean;
nativeSelectMode?: boolean;
listDisplayMode?: boolean;
language?: string;
lable?: string;
styles?: object;
event?: string;
url?: string;
multiselect?: boolean;
multiselectTag?: boolean;
private element: Element | null;
2023-01-06 13:40:18 +03:00
private list: Element | null | undefined;
2023-01-06 14:57:14 +03:00
private options: ICgSelect;
2023-01-06 13:40:18 +03:00
private randomId: string;
private caret: Element | null | undefined;
2023-01-05 18:21:10 +03:00
private category: string;
2023-01-06 21:14:16 +03:00
private selectedItems: string[] | string;
2023-01-05 18:21:10 +03:00
private itemsSelect: IItems[] | string[] | any;
private indexes: number[] = [];
2023-01-06 14:57:14 +03:00
constructor(setting: ICgSelect) {
2023-01-05 18:21:10 +03:00
this.init(setting);
this.render();
2023-01-06 14:07:37 +03:00
this.closeSelectClick();
2023-01-05 18:21:10 +03:00
}
2023-01-06 13:40:18 +03:00
/**
* Приватный метод инициализации экземпляра класса DropDown
2023-01-06 14:07:37 +03:00
* @method init
2023-01-06 13:40:18 +03:00
* @member
* @protected
* @param {ISgSelect} setting передаваемые настройки селекта
* @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта.
* @example
* {
selector: '.cg-dropdown_one',
placeholder: 'Выберите авто',
items: [
'BMW',
{
id: '213sade',
title: 'Opel',
value: 1,
},
'Mersedes',
'MAN',
'max',
],
darkTheme: true,
multiselect: true,
multiselectTag: true,
}
*/
2023-01-06 14:57:14 +03:00
private init(setting: ICgSelect): void {
2023-01-06 13:40:18 +03:00
const { items, multiselect, url, selector } = setting;
2023-01-05 18:21:10 +03:00
this.options = setting;
const elem = document.querySelector(selector);
this.element = elem;
this.element?.addEventListener('click', (e) => {
e.preventDefault();
2023-01-06 13:40:18 +03:00
this.open();
2023-01-05 18:21:10 +03:00
});
this.itemsSelect = [];
2023-01-06 13:40:18 +03:00
2023-01-05 18:21:10 +03:00
if (!items && url) {
2023-01-06 13:40:18 +03:00
this.renderUrl();
return;
2023-01-05 18:21:10 +03:00
}
2023-01-06 13:40:18 +03:00
items.forEach((dataItem: any, index: number) => {
let itemInputs: IDataItem = {
ItemValue: dataItem,
};
this.itemsSelect.push(getFormatItem(itemInputs.ItemValue, index));
});
2023-01-05 18:21:10 +03:00
}
2023-01-06 13:40:18 +03:00
/**
* Приватный метод рендера экземпляра класса DropDown
*@protected
2023-01-06 14:07:37 +03:00
* @method render
2023-01-06 13:40:18 +03:00
* @param {string} select необязательный елемент. Передаеться в метод initSelected
* @description Рендер елементов в селекте.
*/
private render(select?: string): void {
const {
styles,
multiselect,
searchMode,
multiselectTag,
darkTheme,
language,
nativeSelectMode,
listDisplayMode,
} = this.options;
const random = Math.random().toString(36).substring(2, 10);
2023-01-06 13:40:18 +03:00
this.initSelected();
const ulList = document.createElement('ul');
const nativeSelect = createNativeSelect();
let inputSearch: string = '';
let textNode: Text;
this.randomId = random;
ulList.classList.add('list');
this.element?.appendChild(ulList);
this.itemsSelect.forEach((dataItem: IItems | any) => {
this.element?.appendChild(nativeSelect);
const liItem = document.createElement('li');
const nativeOption = createNativeSelectOption();
const strongItem = document.createElement('strong');
liItem.classList.add('list__item');
strongItem.classList.add('category');
2023-01-06 21:14:16 +03:00
if (multiselect) {
2023-01-06 13:40:18 +03:00
const checkBox = document.createElement('input');
checkBox.type = 'checkbox';
checkBox.setAttribute('id', `chbox-${dataItem.id}`);
liItem.appendChild(checkBox);
2023-01-06 21:14:16 +03:00
if (multiselectTag) {
2023-01-06 13:40:18 +03:00
checkBox.classList.add('displayHide');
}
nativeSelect.setAttribute('multiple', 'multiple');
}
if (dataItem.title) {
nativeOption.text = dataItem.title;
nativeOption.value = dataItem.title;
textNode = document.createTextNode(dataItem.title);
nativeSelect.appendChild(nativeOption);
liItem.appendChild(textNode);
ulList.appendChild(liItem);
} else {
// Для отрисовки категорий
textNode = document.createTextNode(dataItem);
strongItem.appendChild(textNode);
ulList.appendChild(strongItem);
}
});
this.list = this.element?.querySelector('.list');
this.caret = this.element?.querySelector('.caret');
2023-01-06 14:07:37 +03:00
this.addOptionsBehaviour();
}
2023-01-05 18:21:10 +03:00
private renderUrl() {}
2023-01-06 13:40:18 +03:00
/**
* Привaтный метод экземпляра класса DropDown
*
2023-01-06 14:07:37 +03:00
* @method initSelected
2023-01-06 13:40:18 +03:00
* @param {string} select необязательный елемент. Используется в методе selectIndex
* @description Отрисовывает и стилизует селект
* @protected
*/
private initSelected(select?: string): void {
const { styles, selected, placeholder, lable, language } = this.options;
if (selected) {
createSelected(this.element, selected);
} else if (placeholder) {
createSelected(this.element, placeholder);
} else {
// if (language && language === 'ru') {
// createSelected(this.#element, ru.selectPlaceholder);
// } else {
// createSelected(this.#element, en.selectPlaceholder);
// }
}
}
2023-01-06 13:40:18 +03:00
/**
* Приватный метод экземпляра класса DropDown
* @protected
* @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl
* @description Открывает список для выбора элемента
2023-01-06 14:07:37 +03:00
* @method open
2023-01-06 13:40:18 +03:00
*/
private open(oneClick?: boolean): void {
if (oneClick === true) {
this.list?.classList.add('open');
this.caret?.classList.add('caret_rotate');
} else {
this.list?.classList.toggle('open');
this.caret?.classList.toggle('caret_rotate');
}
}
2023-01-06 14:07:37 +03:00
/**
* Приватный метод экземпляра класса DropDown
* @protected
* @description Закрывает список
* @method #close
*/
private close(): void {
2023-01-06 14:07:37 +03:00
this.list?.classList.remove('open');
this.caret?.classList.remove('caret_rotate');
}
/**
* Приватный метод экземпляра класса DropDown
* @protected
* @description Закрывает список по клику вне элемента
2023-01-06 14:57:14 +03:00
* @method closeSelectClick
2023-01-06 14:07:37 +03:00
*/
private closeSelectClick(): void {
2023-01-06 14:07:37 +03:00
const dropdown = document.querySelector(`${this.options.selector}`);
document.addEventListener('click', (e) => {
const withinBoundaries = e.composedPath().includes(dropdown!);
if (!withinBoundaries) {
// if (this.btn) {
// return;
// } else {
// this.#close();
// }
this.close();
}
});
}
/**
* Приватный метод экземпляра класса DropDown
* @protected
* @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг.
* @method addOptionsBehaviour
*/
private addOptionsBehaviour() {
const {
multiselect,
placeholder,
selected,
multiselectTag,
searchMode,
closeOnSelect,
darkTheme,
} = this.options;
const options = this.element?.querySelectorAll('.list__item');
2023-01-06 21:14:16 +03:00
const select: HTMLElement | null | undefined = this.element?.querySelector('.selected');
2023-01-06 14:07:37 +03:00
const nativeOption = this.element?.querySelectorAll('.nativeSelect__nativeOption');
const placeholderTextSelect: ITextSelect = {
placeholder: placeholder,
selected: selected,
};
2023-01-06 14:07:37 +03:00
const ulMultipul = document.createElement('ul');
2023-01-06 21:14:16 +03:00
if (multiselect) {
this.selectedItems = [];
2023-01-06 14:07:37 +03:00
ulMultipul.classList.add('multiselect-tag');
select?.classList.add('overflow-hidden');
}
options?.forEach((option: Element, index: number) => {
option.addEventListener('click', (event) => {
2023-01-06 21:14:16 +03:00
const item: IItems = this.itemsSelect[index];
2023-01-06 14:07:37 +03:00
const checkIndex = this.indexes.indexOf(index);
2023-01-06 21:14:16 +03:00
if (closeOnSelect == false || multiselect) {
event.stopPropagation();
event.preventDefault();
}
if (multiselect) {
option.classList.toggle('active');
const checkBox: HTMLInputElement | null = option.querySelector('input[type="checkbox"]');
if (checkBox) {
if (!(event.target instanceof HTMLInputElement)) {
checkBox.checked = !checkBox.checked;
}
if (checkIndex == -1) {
this.indexes.push(index);
nativeOptionMultiple(nativeOption, item.title, true);
select!.textContent = '';
2023-01-09 17:57:56 +03:00
if (multiselectTag) {
if (Array.isArray(this.selectedItems)) {
const dataBreadCrumb: ICreateBreadCrumb = {
option: this.options,
element: this.element,
indexes: this.indexes,
selectedItems: this.selectedItems,
};
this.selectedItems.push(item.title);
select!.appendChild(ulMultipul);
ulMultipul.appendChild(
CreateBreadCrumb(dataBreadCrumb, item.title, index, item.id),
);
}
} else {
if (Array.isArray(this.selectedItems)) {
this.selectedItems.push(item.title);
select!.innerText = this.selectedItems.join(',');
}
}
} else {
2023-01-09 17:57:56 +03:00
if (multiselectTag) {
const tagItem = document.getElementById(`tag-${index}-${item.id}`);
ulMultipul.removeChild<Element>(tagItem!);
}
if (Array.isArray(this.selectedItems)) {
this.selectedItems.splice(checkIndex, 1);
2023-01-09 17:57:56 +03:00
this.indexes.splice(checkIndex, 1);
nativeOptionMultiple(nativeOption, item.title, false);
}
}
2023-01-09 17:57:56 +03:00
if (!this.selectedItems.length) {
getSelectText(placeholderTextSelect, select);
2023-01-09 17:57:56 +03:00
} else {
if (multiselectTag) {
select!.appendChild(ulMultipul);
} else {
if (Array.isArray(this.selectedItems)) {
select!.innerText = this.selectedItems.join(',');
}
}
}
}
} else {
select!.textContent = item.title;
this.selectedItems = item.title;
nativeOptionOrdinary(nativeOption, item.title);
options.forEach((option) => {
option.classList.remove('active');
});
option.classList.add('active');
}
2023-01-06 14:07:37 +03:00
});
});
}
2023-01-05 18:21:10 +03:00
}