Finished in working to TS
This commit is contained in:
		| @@ -24,4 +24,4 @@ | ||||
| ### 00.00.2023 - обновление 0.2.1 | ||||
|  | ||||
| - Весь селект переписан на ts. | ||||
| - Документация и реадми переписаны на Английский. | ||||
| - Исправленны баги и недочеты. | ||||
|   | ||||
| @@ -45,10 +45,9 @@ npm i cg-select | ||||
| ### Пример создния обычного селекта | ||||
|  | ||||
| ```javascript | ||||
| import { DropDown } from 'cg-select/src/cg-select'; | ||||
| import 'cg-select/src/main.scss'; | ||||
| import { CGSelect } from 'cg-select'; | ||||
|  | ||||
| const dropdown = new DropDown({ | ||||
| const dropdown = new CGSelect({ | ||||
|   selector: '.cg-dropdown_selector', | ||||
|   placeholder: 'Выберите авто', | ||||
|   items: [ | ||||
|   | ||||
| @@ -27,7 +27,7 @@ | ||||
|         <nav> | ||||
|           <ul class="navlist"> | ||||
|             <li><a href="">Home</a></li> | ||||
|             <!-- <li><a href="/documentation/index.html">Documentation</a></li> --> | ||||
|             <li><a href="/documentation/index.html">Documentation</a></li> | ||||
|           </ul> | ||||
|         </nav> | ||||
|       </header> | ||||
| @@ -46,7 +46,7 @@ | ||||
|           <button type="button" class="check-code" id="first">Посмотреть код</button> | ||||
|           <code id="codeFirst"> | ||||
|             <pre> | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|                 selector: <span class="code__string">'.cg-dropdown_one',</span>  | ||||
|                 placeholder: <span class="code__string">'Выберите авто',</span>  | ||||
|                 lable: <span class="code__string">'EXAMPLE',</span>  | ||||
| @@ -89,7 +89,7 @@ | ||||
|           <button type="button" class="check-code" id="Native">Посмотреть код</button> | ||||
|           <code id="codeNative"> | ||||
|             <pre> | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|                 selector: <span class="code__string">'.cg-dropdown_one',</span>  | ||||
|                 placeholder: <span class="code__string">'Выберите авто',</span>  | ||||
|                 nativeSelectMode: <span class="code__keyword">true,</span> | ||||
| @@ -133,7 +133,7 @@ | ||||
|  | ||||
|           <code id="codeSix"> | ||||
|             <pre> | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|               <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|                 selector: <span class="code__string">'.cg-dropdown_listDisplayMode',</span>  | ||||
|                 placeholder: <span class="code__string">'Выберите авто',</span>  | ||||
|                 listDisplayMode: <span class="code__keyword">true,</span> | ||||
| @@ -171,7 +171,7 @@ | ||||
|  | ||||
|         <code id="codeSecond"> | ||||
|           <pre> | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|               selector: <span class="code__string">'.cg-dropdown_three',</span>  | ||||
|               placeholder: <span class="code__string">'URL',</span>  | ||||
|               url: <span class="code__string">'https://jsonplaceholder.typicode.com/users',</span>             | ||||
| @@ -201,7 +201,7 @@ | ||||
|  | ||||
|         <code id="codeThird"> | ||||
|           <pre> | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|               selector: <span class="code__string">'.cg-dropdown_categories',</span>  | ||||
|               placeholder: <span class="code__string">'Выберите регион',</span>  | ||||
|               searchMode: <span class="code__keyword">true,</span> | ||||
| @@ -267,7 +267,7 @@ | ||||
|  | ||||
|         <code id="codeFourth"> | ||||
|           <pre> | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|               selector: <span class="code__string">'.cg-dropdown_usedBtn',</span>  | ||||
|               placeholder: <span class="code__string">'Выберите авто',</span>  | ||||
|               searchMode: <span class="code__keyword">true,</span> | ||||
| @@ -323,7 +323,7 @@ | ||||
|         <button type="button" class="check-code" id="fifth">Посмотреть код</button> | ||||
|         <code id="codeFifth"> | ||||
|           <pre> | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">DropDown</span>({ | ||||
|             <span class="code__keyword">const</span> <span class="code__var">dropdown</span> = <span class="code__keyword">new</span> <span class="code__class">CGSelect</span>({ | ||||
|               selector: <span class="code__string">'.cg-dropdown_checkboxDisable',</span>  | ||||
|               placeholder: <span class="code__string">'Выберите авто',</span>  | ||||
|               searchMode: <span class="code__keyword">true,</span> | ||||
| @@ -356,5 +356,4 @@ | ||||
|     </div> | ||||
|   </body> | ||||
|   <script type="module" src="index.js"></script> | ||||
|   <!-- <script type="module" src="indexTs.ts"></script> --> | ||||
| </html> | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { CGSelect } from '../src/cg-selectTS'; | ||||
| import { CGSelect } from '../src/cg-select'; | ||||
| import './example'; | ||||
|  | ||||
| // ------------------------------Обычный селект-------------------- | ||||
|   | ||||
| @@ -1,234 +0,0 @@ | ||||
| // import { CGSelect } from '../src/cg-selectTS'; | ||||
| // import './example'; | ||||
|  | ||||
| // // ------------------------------Обычный селект-------------------- | ||||
| // const dropdn = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_one', | ||||
| //   placeholder: 'Выберите авто', | ||||
| //   lable: 'EXAMPLE', | ||||
| //   items: [ | ||||
| //     'BMW', | ||||
| //     { | ||||
| //       id: '213sade', | ||||
| //       title: 'Opel', | ||||
| //       value: 1, | ||||
| //     }, | ||||
| //     'Mersedes', | ||||
| //     'MAN', | ||||
| //     'Ferari', | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //   }, | ||||
| // }); | ||||
|  | ||||
| // // ------------------------------NativeSelect----------------------- | ||||
| // const dropdownNativeSelect = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_selectNative', | ||||
| //   placeholder: 'Выберите авто', | ||||
| //   nativeSelectMode: true, | ||||
| //   items: [ | ||||
| //     'BMW', | ||||
| //     { | ||||
| //       id: '213sade', | ||||
| //       title: 'Opel', | ||||
| //       value: 1, | ||||
| //     }, | ||||
| //     'Mersedes', | ||||
| //     'MAN', | ||||
| //     'Ferari', | ||||
| //     'Kamaz', | ||||
| //     'Ural', | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //   }, | ||||
| // }); | ||||
|  | ||||
| // // console.log(); | ||||
|  | ||||
| // // ------------------------------listDisplayMode-------------------- | ||||
| // const dropdownlistDisplayMode = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_listDisplayMode', | ||||
| //   placeholder: 'Выберите авто', | ||||
| //   listDisplayMode: true, | ||||
| //   items: [ | ||||
| //     'BMW', | ||||
| //     { | ||||
| //       id: '213sade', | ||||
| //       title: 'Opel', | ||||
| //       value: 1, | ||||
| //     }, | ||||
| //     'Mersedes', | ||||
| //     'MAN', | ||||
| //     'Ferari', | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //   }, | ||||
| // }); | ||||
|  | ||||
| // // ------------------------------URL-------------------- | ||||
| // const dropdown3 = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_three', | ||||
| //   placeholder: 'URL', | ||||
| //   url: 'https://jsonplaceholder.typicode.com/users', | ||||
| //   searchMode: true, | ||||
| //   darkTheme: false, | ||||
| //   language: 'ru', | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //   }, | ||||
| // }); | ||||
|  | ||||
| // // --------------------------------Категории-------------------------- | ||||
| // const dropdown4 = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_categories', | ||||
| //   placeholder: 'Выберите регион', | ||||
| //   searchMode: true, | ||||
| //   items: [ | ||||
| //     { | ||||
| //       category: 'Russia', | ||||
| //       categoryItems: [ | ||||
| //         { | ||||
| //           id: '28qwds', | ||||
| //           title: 'Москва', | ||||
| //           value: 0, | ||||
| //         }, | ||||
| //         , | ||||
| //         'Ростов-на-дону', | ||||
| //         'Саратов', | ||||
| //         'Волгоград', | ||||
| //         'Донецк', | ||||
| //       ], | ||||
| //     }, | ||||
| //     { | ||||
| //       category: 'USA', | ||||
| //       categoryItems: ['Alabama', 'Texas', 'Colorado', 'Klirens', 'Los-Angeles'], | ||||
| //     }, | ||||
| //     { | ||||
| //       category: 'France', | ||||
| //       categoryItems: ['Paris'], | ||||
| //     }, | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //     placeholder: { | ||||
| //       maxWidth: '500px ', | ||||
| //     }, | ||||
| //   }, | ||||
| //   multiselect: true, | ||||
| //   multiselectTag: true, | ||||
| // }); | ||||
|  | ||||
| // //----------------управление с помощью кнопок---------------------------------- | ||||
| // const dropdownBtn = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_usedBtn', | ||||
| //   placeholder: 'Выберите авто', | ||||
| //   searchMode: true, | ||||
| //   items: [ | ||||
| //     'BMW', | ||||
| //     { | ||||
| //       id: '213sade', | ||||
| //       title: 'Opel', | ||||
| //       value: 1, | ||||
| //     }, | ||||
| //     'Mersedes', | ||||
| //     'MAN', | ||||
| //     'max', | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //       color: 'black', | ||||
| //       backgroundColor: 'rgb(176 223 167)', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //       color: 'black', | ||||
| //       backgroundColor: 'rgb(176 223 167)', | ||||
| //     }, | ||||
| //     caret: { | ||||
| //       borderTop: '6px solid black', | ||||
| //     }, | ||||
| //     search: { | ||||
| //       backgroundColor: '#d7ffff', | ||||
| //       borderRadius: '5px', | ||||
| //       borderBottom: 'none', | ||||
| //       width: '95%', | ||||
| //       color: 'black', | ||||
| //     }, | ||||
| //   }, | ||||
| //   multiselect: true, | ||||
| // }); | ||||
|  | ||||
| // const buttonOpen = document.querySelector('.button__open'); | ||||
| // const buttonClose = document.querySelector('.button__close'); | ||||
|  | ||||
| // dropdownBtn.buttonControl(buttonOpen!, 'open'); | ||||
| // dropdownBtn.buttonControl(buttonClose!, 'close'); | ||||
|  | ||||
| // //-------------------------Функция Disabled---------------------------------- | ||||
| // const dropdownDisabled = new CGSelect({ | ||||
| //   selector: '.cg-dropdown_checkboxDisable', | ||||
| //   placeholder: 'Выберите авто', | ||||
| //   searchMode: true, | ||||
| //   items: [ | ||||
| //     'BMW', | ||||
| //     { | ||||
| //       id: '213sade', | ||||
| //       title: 'Opel', | ||||
| //       value: 1, | ||||
| //     }, | ||||
| //     'Mersedes', | ||||
| //     'MAN', | ||||
| //     'max', | ||||
| //   ], | ||||
| //   styles: { | ||||
| //     head: { | ||||
| //       width: '830px', | ||||
| //     }, | ||||
| //     list: { | ||||
| //       width: '824px', | ||||
| //     }, | ||||
| //     placeholder: { | ||||
| //       maxWidth: '500px ', | ||||
| //     }, | ||||
| //   }, | ||||
| //   multiselect: true, | ||||
| // }); | ||||
| // dropdownDisabled.disabled(true); | ||||
| // let chbox = document.getElementById('checkboxDisable') as HTMLInputElement; | ||||
|  | ||||
| // chbox!.addEventListener('click', () => { | ||||
| //   if (chbox!.checked == true) { | ||||
| //     dropdownDisabled.disabled(false); | ||||
| //   } else { | ||||
| //     dropdownDisabled.disabled(true); | ||||
| //   } | ||||
| // }); | ||||
							
								
								
									
										2
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								index.js
									
									
									
									
									
								
							| @@ -1,3 +1,3 @@ | ||||
| import { CGSelect } from './src/cg-selectTS'; | ||||
| import { CGSelect } from './src/cg-select'; | ||||
|  | ||||
| export default CGSelect; | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|   "homepage": "https://cg-select.itguild.info", | ||||
|   "scripts": { | ||||
|     "start": "parcel example/index.html -p 4500 --open ", | ||||
|     "build": "parcel build example/index.html --no-cache", | ||||
|     "build": "parcel build example/index.js --no-cache", | ||||
|     "deploy": "gh-pages -d dist", | ||||
|     "predeploy": "npm run build" | ||||
|   }, | ||||
|   | ||||
							
								
								
									
										923
									
								
								src/cg-select.js
									
									
									
									
									
								
							
							
						
						
									
										923
									
								
								src/cg-select.js
									
									
									
									
									
								
							| @@ -1,923 +0,0 @@ | ||||
| import { | ||||
|   createSelected, | ||||
|   customStyles, | ||||
|   getFormatItem, | ||||
|   getSelectText, | ||||
|   customStylesFormat, | ||||
|   nativeOptionMultiple, | ||||
|   nativeOptionOrdinary, | ||||
|   clearSelect, | ||||
| } from './components/utils'; | ||||
| import { | ||||
|   createBreadcrumb, | ||||
|   createInputSearch, | ||||
|   createNativeSelectOption, | ||||
|   createNativeSelect, | ||||
| } from './components/create-element'; | ||||
| import { ru, en } from './language/language'; | ||||
| import './main.scss' | ||||
|  | ||||
| /** | ||||
|  * @class Описание класса DropDown | ||||
|  * @description Этот класс реализовывает функционал кастомного селекта, с возможностями кастомизации. | ||||
|  * @author Овсяников Максим | ||||
|  */ | ||||
| export class DropDown { | ||||
|   /** | ||||
|    * Созданный HTML елемент | ||||
|    * @type {HTMLElement} | ||||
|    */ | ||||
|   #element; | ||||
|   /** | ||||
|    * Созданный список(ul), с классом list | ||||
|    * @type {HTMLElement} | ||||
|    */ | ||||
|   #list; | ||||
|   /** | ||||
|    * Настройки селекта передаваемые при создании экземпляра класса | ||||
|    * @type {object} | ||||
|    */ | ||||
|   #options; | ||||
|   /** | ||||
|    * Переменная для управления каретки | ||||
|    * @type {HTMLElement} | ||||
|    */ | ||||
|   #caret; | ||||
|   /** | ||||
|    * Массив переданных элементов | ||||
|    * @type {object[]} | ||||
|    */ | ||||
|   #items; | ||||
|   /** | ||||
|    * Переданные категории | ||||
|    * @type {string} | ||||
|    */ | ||||
|   #category; | ||||
|   /** | ||||
|    * Выбранный или массив выбранных элементов из списка | ||||
|    * @type {object[] | object} | ||||
|    */ | ||||
|   #selectedItems; | ||||
|   /** | ||||
|    * Массив индексов выбранных элементов | ||||
|    * @type {number[]} | ||||
|    */ | ||||
|   #indexes = []; | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @returns {string[] | string | null} Возвращает выбранные элемент(ы) в виде массива/элемента/null | ||||
|    * @description Геттер возвращающий выбранные элемент(ы) селекта | ||||
|    */ | ||||
|   get value() { | ||||
|     return this.#selectedItems ?? null; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @returns {number | number[]}Возвращает индексы выбранных элемента(ов) в виде массива/пустой массив | ||||
|    * @description Геттер возвращающий индексы выбранных элемента(ов) селекта | ||||
|    */ | ||||
|   get indexes() { | ||||
|     return this.#indexes ?? []; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * | ||||
|    * @param {object} options Объект принимающий настройки селекта | ||||
|    * @constructor Конструктор класса DropDown | ||||
|    * @description  Конструктор принимает объект и рендерит селект. | ||||
|    * @example | ||||
|    * options = { | ||||
|    *  selector: 'Уникальный селектор', | ||||
|       selected: 'Выбранный элемент', | ||||
|       placeholder: '...', | ||||
|       lable: '...' | ||||
|       items: [string|number|object], | ||||
|       darkTheme: true/false, | ||||
|       searchMode: true/false, | ||||
|       closeOnSelect:  true/false, | ||||
|       nativeSelectMode: true/false, | ||||
|       listDisplayMode: true/false, | ||||
|       language: 'ru/en', | ||||
|       styles: { | ||||
|         head: { | ||||
|           background: '...', | ||||
|         }, | ||||
|         list: {...}, | ||||
|         chips: {...}, | ||||
|         caret: {...}, | ||||
|         placeholder: {...}, | ||||
|         lable: {..}, | ||||
|       }, | ||||
|       event: '...', | ||||
|       url: 'http/...', | ||||
|       multiselect: true/false, | ||||
|       multiselectTag: true/false, | ||||
|    * } | ||||
|       | ||||
|    */ | ||||
|   constructor(options = {}) { | ||||
|     this.#init(options); | ||||
|     this.#render(); | ||||
|     this.#initEvent(); | ||||
|     this.#closeSelectClick(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {string | object} item добавляемый елемент | ||||
|    * @description добавляет переданный элемент в конец списка и перерисовывает список. Не может использоваться при передачи элементов с категорями | ||||
|    * @method addItem | ||||
|    */ | ||||
|   addItem(item) { | ||||
|     if (this.#category) { | ||||
|       console.log('can`t add item to category'); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!item) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     const index = this.#items.length; | ||||
|  | ||||
|     this.#items.push(getFormatItem(item, index)); | ||||
|     this.#render(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {number} index индекс удаляемого элемента | ||||
|    * @description удаляет елемент по индексу из списка и перерисовывает его. Не может использоваться при передачи элементов с категорями. | ||||
|    * @method deleteItem | ||||
|    */ | ||||
|   deleteItem(index) { | ||||
|     if (this.#category) { | ||||
|       console.log('can`t add item to category'); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const item = this.#items[index]; | ||||
|  | ||||
|     this.#items.splice(index, 1); | ||||
|     this.#render(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @description удаляет все елементы из списка и перерисовывает его. | ||||
|    * @method deleteItemAll | ||||
|    */ | ||||
|   deleteItemAll() { | ||||
|     this.#items.splice(0, this.#items.length); | ||||
|     this.#render(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {number} index индекс выбранного элемента | ||||
|    * @description  выбирает элемент который будет изначально отрисовываться в селекте | ||||
|    * @method selectIndex | ||||
|    */ | ||||
|   selectIndex(index) { | ||||
|     if (this.#category) { | ||||
|       console.log('can`t add item to category'); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const options = this.#element.querySelectorAll('.list__item'); | ||||
|  | ||||
|     if (index > options.length) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const select = options[index].innerText; | ||||
|     this.#render(select); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {number} numberItem номер возвращаемого элемента | ||||
|    * @returns {HTMLElement} возвращает ссылку на выбранный HTML элемент | ||||
|    * @method getElement | ||||
|    */ | ||||
|   getElement(numberItem) { | ||||
|     if (numberItem > this.#items.length) { | ||||
|       return; | ||||
|     } | ||||
|     return this.#items[numberItem]; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {boolean} value - Передаваемый параметр для добавления атрибута disabled; | ||||
|    * @description Метод позволяющий переключать состояние селекта disabled, | ||||
|    * @method disabled | ||||
|    */ | ||||
|   disabled(value) { | ||||
|     if (typeof value !== 'boolean') { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const select = this.#element.querySelector('.cg-select'); | ||||
|     const nativeSelect = this.#element.querySelector('.nativeSelect'); | ||||
|     if (value === true) { | ||||
|       this.#element.setAttribute('disabled', true); | ||||
|       nativeSelect.setAttribute('disabled', true); | ||||
|       select.classList.add('disabled'); | ||||
|     } else { | ||||
|       this.#element.removeAttribute('disabled'); | ||||
|       nativeSelect.removeAttribute('disabled'); | ||||
|       select.classList.remove('disabled'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {HTMLInputElement} button - HTML кнопка | ||||
|    * @param {string} method - метод открытия open/close | ||||
|    * @description Метод позволяющий открывать/закрывать селект с помощью кнопок | ||||
|    * @method buttonControl | ||||
|    */ | ||||
|   buttonControl(button, method) { | ||||
|     const { listDisplayMode } = this.#options; | ||||
|  | ||||
|     if (listDisplayMode === true) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     this.btn = button; | ||||
|     button.addEventListener('click', () => { | ||||
|       if (method.toLowerCase() === 'open') { | ||||
|         this.#open(true); | ||||
|       } else if (method.toLowerCase() === 'close') { | ||||
|         this.#close(); | ||||
|       } else { | ||||
|         return; | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод экземпляра класса DropDown | ||||
|    * @param {object} language объект в котором находятся поля для подключения языка имеет два обязательных поля placeholder, textInListSearch | ||||
|    * @description метод позволяющий заменить плейсхолдер в поиске и текст который выводится если нет результата | ||||
|    * @method addLanguage | ||||
|    */ | ||||
|   addLanguage(language) { | ||||
|     const { placeholder, textInListSearch, selectPlaceholder } = language; | ||||
|     const { searchMode } = this.#options; | ||||
|  | ||||
|     const select = this.#element.querySelector('.selected'); | ||||
|     const textNodeSelect = document.createTextNode(selectPlaceholder); | ||||
|     select.appendChild(textNodeSelect); | ||||
|  | ||||
|     if (searchMode && searchMode == true) { | ||||
|       const search = this.#element.querySelector('.inputSearch'); | ||||
|       const textNoRezult = this.#element.querySelector('.noRezult'); | ||||
|       const textNode = document.createTextNode(textInListSearch); | ||||
|  | ||||
|       search.setAttribute('placeholder', placeholder); | ||||
|       search.setAttribute('placeholder', placeholder); | ||||
|  | ||||
|       textNoRezult.innerText = ''; | ||||
|       textNoRezult.appendChild(textNode); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод инициализации экземпляра класса DropDown | ||||
|    * @method #init | ||||
|    * @member | ||||
|    * @protected | ||||
|    * @param {object} options передаваемые настройки селекта | ||||
|    * @description Приватный метод. Общая инициализация селекта. Получение настоек и преобразвание элементов селекта. | ||||
|    * @example | ||||
|    *  { | ||||
|         selector: '.cg-dropdown_one', | ||||
|         placeholder: 'Выберите авто', | ||||
|         items: [ | ||||
|           'BMW', | ||||
|           { | ||||
|             id: '213sade', | ||||
|             title: 'Opel', | ||||
|             value: 1, | ||||
|           }, | ||||
|           'Mersedes', | ||||
|           'MAN', | ||||
|           'max', | ||||
|         ], | ||||
|         darkTheme: true, | ||||
|         multiselect: true, | ||||
|         multiselectTag: true, | ||||
|       } | ||||
|    */ | ||||
|   #init(options) { | ||||
|     this.#options = options; | ||||
|     const { items, multiselect, url } = this.#options; | ||||
|  | ||||
|     const elem = document.querySelector(options.selector); | ||||
|  | ||||
|     //TODO: для теста в реакте нужно пересмотреть необходимость этой проверки! | ||||
|     // if (!elem) { | ||||
|     //   throw new Error(`Element with selector ${options.selector}`); | ||||
|     // } | ||||
|  | ||||
|     this.#element = elem; | ||||
|  | ||||
|     this.#element.addEventListener('click', (e) => { | ||||
|       e.preventDefault(); | ||||
|       this.#open(); | ||||
|     }); | ||||
|  | ||||
|     this.#items = []; | ||||
|  | ||||
|     if (multiselect && multiselect == true) { | ||||
|       this.#selectedItems = []; | ||||
|     } | ||||
|  | ||||
|     if (!items && url) { | ||||
|       this.#renderUrl(); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     items.forEach((dataItem, index) => { | ||||
|       if (dataItem.category && dataItem.categoryItems) { | ||||
|         this.#category = dataItem.category; | ||||
|  | ||||
|         this.#items.push(this.#category); | ||||
|         dataItem.categoryItems.forEach((categoryItem, indexCategory) => { | ||||
|           this.#items.push(getFormatItem(categoryItem, indexCategory)); | ||||
|         }); | ||||
|       } else { | ||||
|         this.#items.push(getFormatItem(dataItem, index)); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Привaтный метод экземпляра класса DropDown | ||||
|    * | ||||
|    * @method #initSelected | ||||
|    * @param {string} select необязательный елемент. Используется в методе selectIndex | ||||
|    * @description Отрисовывает и стилизует селект | ||||
|    * @protected | ||||
|    */ | ||||
|   #initSelected(select) { | ||||
|     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); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (select) { | ||||
|       createSelected(this.#element, select, styles); | ||||
|     } | ||||
|  | ||||
|     if (lable) { | ||||
|       const lableItem = document.createElement('h1'); | ||||
|       const textLable = document.createTextNode(lable); | ||||
|  | ||||
|       lableItem.appendChild(textLable); | ||||
|       lableItem.classList.add('label'); | ||||
|  | ||||
|       this.#element.insertAdjacentElement('beforebegin', lableItem); | ||||
|     } | ||||
|  | ||||
|     if (styles) { | ||||
|       customStyles(this.#element, styles); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод рендера экземпляра класса DropDown | ||||
|    *@protected | ||||
|    * @method #render | ||||
|    * @param {string} select  необязательный елемент. Передаеться в метод initSelected | ||||
|    * @description Рендер елементов в селекте. | ||||
|    */ | ||||
|   #render(select) { | ||||
|     const { | ||||
|       styles, | ||||
|       multiselect, | ||||
|       searchMode, | ||||
|       multiselectTag, | ||||
|       darkTheme, | ||||
|       language, | ||||
|       nativeSelectMode, | ||||
|       listDisplayMode, | ||||
|     } = this.#options; | ||||
|  | ||||
|     const random = Math.random().toString(36).substring(2, 10); | ||||
|  | ||||
|     if (select || (select && styles)) { | ||||
|       this.#initSelected(select); | ||||
|       customStyles(this.#element, styles); | ||||
|     } else { | ||||
|       this.#initSelected(); | ||||
|     } | ||||
|  | ||||
|     const ulList = document.createElement('ul'); | ||||
|     const nativeSelect = createNativeSelect(); | ||||
|  | ||||
|     let inputSearch = ''; | ||||
|     this.random = random; | ||||
|  | ||||
|     if (searchMode) { | ||||
|       if (language === 'ru') { | ||||
|         inputSearch = createInputSearch(random, ru.placeholder); | ||||
|       } else { | ||||
|         inputSearch = createInputSearch(random, en.placeholder); | ||||
|       } | ||||
|       const { search } = styles; | ||||
|       customStylesFormat(search, inputSearch); | ||||
|       ulList.appendChild(inputSearch); | ||||
|     } | ||||
|  | ||||
|     ulList.classList.add('list'); | ||||
|  | ||||
|     if (styles) { | ||||
|       const { list } = styles; | ||||
|       customStylesFormat(list, ulList); | ||||
|     } | ||||
|  | ||||
|     this.#element.appendChild(ulList); | ||||
|  | ||||
|     this.#items.forEach((dataItem) => { | ||||
|       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'); | ||||
|  | ||||
|       if (multiselect && multiselect == true) { | ||||
|         const checkBox = document.createElement('input'); | ||||
|         checkBox.type = 'checkbox'; | ||||
|         checkBox.setAttribute('id', `chbox-${dataItem.id}`); | ||||
|         liItem.appendChild(checkBox); | ||||
|  | ||||
|         if (multiselectTag && multiselectTag == true) { | ||||
|           checkBox.classList.add('displayHide'); | ||||
|         } | ||||
|  | ||||
|         nativeSelect.setAttribute('multiple', 'multiple'); | ||||
|       } | ||||
|  | ||||
|       let textNode = ''; | ||||
|  | ||||
|       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.#items.filter((item, index) => { | ||||
|       if (typeof item !== 'object') { | ||||
|         this.#items.splice(index, 1); | ||||
|       } | ||||
|       return item; | ||||
|     }); | ||||
|  | ||||
|     if (darkTheme == false) { | ||||
|       this.#checkTheme(); | ||||
|     } | ||||
|  | ||||
|     if (nativeSelectMode === true) { | ||||
|       this.#selectMode(nativeSelectMode); | ||||
|     } | ||||
|  | ||||
|     this.#list = this.#element.querySelector('.list'); | ||||
|     this.#caret = this.#element.querySelector('.caret'); | ||||
|  | ||||
|     if (listDisplayMode === true) { | ||||
|       this.#displayMode(listDisplayMode); | ||||
|     } | ||||
|  | ||||
|     this.#addOptionsBehaviour(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод рендера экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @method #checkTheme | ||||
|    * @description Изменяет цветовую схему с темной на светлую. | ||||
|    */ | ||||
|   #checkTheme() { | ||||
|     const { darkTheme, searchMode } = this.#options; | ||||
|  | ||||
|     const select = this.#element.querySelector('.cg-select'); | ||||
|     const caret = this.#element.querySelector('.caret'); | ||||
|     const list = this.#element.querySelector('ul.list'); | ||||
|     const search = this.#element.querySelector('.inputSearch'); | ||||
|  | ||||
|     if (darkTheme == false) { | ||||
|       select.classList.add('selectWhite'); | ||||
|       caret.classList.add('caretWhite'); | ||||
|       list.classList.add('listWhite'); | ||||
|  | ||||
|       if (searchMode == true) { | ||||
|         search.classList.add('inputWhite'); | ||||
|       } | ||||
|     } else if (darkTheme == true || !darkTheme) { | ||||
|       return; | ||||
|     } else { | ||||
|       throw new Error('Styles error or invalid value entered!'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод рендера экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @method #renderUrl | ||||
|    * @description Рендер елементов в селекте переданных с URL и их настойка | ||||
|    */ | ||||
|   async #renderUrl() { | ||||
|     const { url, items, multiselect, multiselectTag } = this.#options; | ||||
|  | ||||
|     if (items) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (!url) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     const response = await fetch(url); | ||||
|     const dataUrl = await response.json(); | ||||
|  | ||||
|     const nativeSelect = createNativeSelect(); | ||||
|  | ||||
|     dataUrl.forEach((dataItem, index) => { | ||||
|       const item = { | ||||
|         id: dataItem.id, | ||||
|         title: dataItem.name, | ||||
|         value: index, | ||||
|       }; | ||||
|       const ulUrl = this.#element.querySelector('.list'); | ||||
|  | ||||
|       const nativeOption = createNativeSelectOption(); | ||||
|       const liUrl = document.createElement('li'); | ||||
|       const textUrl = document.createTextNode(item.title); | ||||
|  | ||||
|       if (multiselect && multiselect == true) { | ||||
|         const checkBox = document.createElement('input'); | ||||
|         checkBox.type = 'checkbox'; | ||||
|         if (multiselectTag && multiselectTag == true) { | ||||
|           checkBox.classList.add('displayHide'); | ||||
|         } | ||||
|  | ||||
|         checkBox.setAttribute('id', `chbox-${item.id}`); | ||||
|         nativeSelect.setAttribute('multiple', 'multiple'); | ||||
|  | ||||
|         liUrl.appendChild(checkBox); | ||||
|       } | ||||
|  | ||||
|       liUrl.classList.add('list__item'); | ||||
|       nativeOption.value = item.title; | ||||
|       nativeOption.text = item.title; | ||||
|  | ||||
|       nativeSelect.appendChild(nativeOption); | ||||
|       liUrl.appendChild(textUrl); | ||||
|       ulUrl.appendChild(liUrl); | ||||
|  | ||||
|       this.#items.push(item); | ||||
|     }); | ||||
|  | ||||
|     this.#element.appendChild(nativeSelect); | ||||
|  | ||||
|     this.#items.filter((item, index) => { | ||||
|       if (typeof item !== 'object') { | ||||
|         this.#items.splice(index, 1); | ||||
|       } | ||||
|       return item; | ||||
|     }); | ||||
|  | ||||
|     this.#addOptionsBehaviour(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @param {boolean} oneClick необязательный параметр передаваемый из функции buttonControl | ||||
|    * @description Открывает список для выбора элемента | ||||
|    * @method #open | ||||
|    */ | ||||
|   #open(oneClick) { | ||||
|     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'); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @description Закрывает список | ||||
|    * @method #close | ||||
|    */ | ||||
|   #close() { | ||||
|     this.#list.classList.remove('open'); | ||||
|     this.#caret.classList.remove('caret_rotate'); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @description Метод реализовывающий выбор элементов в разных режимах. Обычный/Мультиселект/Мультиселект + Мультиселект Таг. | ||||
|    * @method #addOptionsBehaviour | ||||
|    */ | ||||
|   #addOptionsBehaviour() { | ||||
|     const { | ||||
|       multiselect, | ||||
|       placeholder, | ||||
|       selected, | ||||
|       multiselectTag, | ||||
|       searchMode, | ||||
|       closeOnSelect, | ||||
|       darkTheme, | ||||
|     } = this.#options; | ||||
|  | ||||
|     const options = this.#element.querySelectorAll('.list__item'); | ||||
|     const select = this.#element.querySelector('.selected'); | ||||
|     const nativeOption = this.#element.querySelectorAll('.nativeSelect__nativeOption'); | ||||
|  | ||||
|     const ulMultipul = document.createElement('ul'); | ||||
|  | ||||
|     if (multiselect && multiselect == true) { | ||||
|       ulMultipul.classList.add('multiselect-tag'); | ||||
|       select.classList.add('overflow-hidden'); | ||||
|     } | ||||
|  | ||||
|     if (searchMode && searchMode === true) { | ||||
|       this.#searchMode(this.random); | ||||
|     } | ||||
|  | ||||
|     options.forEach((option, index) => { | ||||
|       option.addEventListener('click', (event) => { | ||||
|         const dataSelectText = { | ||||
|           placeholder, | ||||
|           selected, | ||||
|           selectedItems: this.#selectedItems, | ||||
|           indexes: this.#indexes, | ||||
|           darkTheme, | ||||
|           multiselectTag, | ||||
|         }; | ||||
|  | ||||
|         const item = this.#items[index]; | ||||
|  | ||||
|         if (closeOnSelect == false || (multiselect && multiselect == true)) { | ||||
|           event.stopPropagation(); | ||||
|           event.preventDefault(); | ||||
|         } | ||||
|  | ||||
|         const checkIndex = this.#indexes.indexOf(index); | ||||
|  | ||||
|         if (multiselect && multiselect == true) { | ||||
|           option.classList.toggle('active'); | ||||
|           const checkBox = option.querySelector('input[type="checkbox"]'); | ||||
|  | ||||
|           if (checkBox) { | ||||
|             if (!(event.target instanceof HTMLInputElement)) { | ||||
|               checkBox.checked = !checkBox.checked; | ||||
|             } | ||||
|  | ||||
|             if (checkIndex === -1) { | ||||
|               nativeOptionMultiple(nativeOption, item.title, true); | ||||
|               this.#indexes.push(index); | ||||
|               select.innerText = ''; | ||||
|  | ||||
|               if (multiselectTag && multiselectTag == true) { | ||||
|                 this.#selectedItems.push(item); | ||||
|                 select.appendChild(ulMultipul); | ||||
|  | ||||
|                 const data = { | ||||
|                   option: this.#options, | ||||
|                   element: this.#element, | ||||
|                   indexes: this.#indexes, | ||||
|                   selectedItems: this.#selectedItems, | ||||
|                 }; | ||||
|  | ||||
|                 ulMultipul.appendChild(createBreadcrumb(data, item.title, index, item.id)); | ||||
|               } else { | ||||
|                 this.#selectedItems.push(item.title); | ||||
|                 select.innerText = this.#selectedItems; | ||||
|               } | ||||
|             } else { | ||||
|               if (multiselectTag && multiselectTag == true) { | ||||
|                 const tagItem = document.getElementById(`tag-${index}-${item.id}`); | ||||
|                 ulMultipul.removeChild(tagItem); | ||||
|               } | ||||
|  | ||||
|               this.#indexes.splice(checkIndex, 1); | ||||
|               this.#selectedItems.splice(checkIndex, 1); | ||||
|               nativeOptionMultiple(nativeOption, item.title, false); | ||||
|             } | ||||
|  | ||||
|             if (!this.#selectedItems.length) { | ||||
|               getSelectText(dataSelectText, select); | ||||
|             } else { | ||||
|               if (multiselectTag && multiselectTag == true) { | ||||
|                 select.appendChild(ulMultipul); | ||||
|               } else { | ||||
|                 select.innerText = this.#selectedItems; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           select.innerText = item.title; | ||||
|           this.#selectedItems = item; | ||||
|  | ||||
|           nativeOptionOrdinary(nativeOption, item.title); | ||||
|  | ||||
|           options.forEach((option) => { | ||||
|             option.classList.remove('active'); | ||||
|           }); | ||||
|           option.classList.add('active'); | ||||
|         } | ||||
|  | ||||
|         clearSelect(select, this.#element, dataSelectText); | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Метод который реализует поиск элементов в селекте | ||||
|    * @protected | ||||
|    * @param {string} random уникальное значение для input элемента. | ||||
|    * @method #searchMode | ||||
|    */ | ||||
|   #searchMode(random) { | ||||
|     const { language } = this.#options; | ||||
|  | ||||
|     const input = this.#element.querySelector(`#searchSelect-${random}`); | ||||
|     const searchSelect = this.#element.querySelectorAll('.list__item'); | ||||
|     const result = document.createElement('p'); | ||||
|  | ||||
|     let textNode = ''; | ||||
|     if (language && language === 'ru') { | ||||
|       textNode = document.createTextNode(`${ru.textInListSearch}`); | ||||
|     } else { | ||||
|       textNode = document.createTextNode(`${en.textInListSearch}`); | ||||
|     } | ||||
|  | ||||
|     result.appendChild(textNode); | ||||
|     result.classList.add('displayHide'); | ||||
|     result.classList.add('noRezult'); | ||||
|     input.parentElement.appendChild(result); | ||||
|  | ||||
|     input.addEventListener('click', (e) => { | ||||
|       e.stopPropagation(); | ||||
|     }); | ||||
|  | ||||
|     input.oninput = function () { | ||||
|       let valueSearch = this.value.trim().toLowerCase(); | ||||
|       let anyMatch = false; | ||||
|  | ||||
|       if (valueSearch != '') { | ||||
|         searchSelect.forEach((elem) => { | ||||
|           let isMatching = new RegExp(valueSearch, 'gi').test(elem.textContent); | ||||
|           anyMatch = anyMatch || isMatching; | ||||
|  | ||||
|           if (elem.textContent.toLowerCase().search(valueSearch) == -1) { | ||||
|             elem.classList.add('displayHide'); | ||||
|           } else { | ||||
|             elem.classList.remove('displayHide'); | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|         result.classList.toggle('displayHide', anyMatch); | ||||
|       } else { | ||||
|         searchSelect.forEach((elem) => { | ||||
|           elem.classList.remove('displayHide'); | ||||
|           result.classList.add('displayHide'); | ||||
|         }); | ||||
|       } | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @description Открывает и закрывает список по переданному эвенту | ||||
|    * @method #initEvent | ||||
|    */ | ||||
|   #initEvent() { | ||||
|     const { event } = this.#options; | ||||
|     if (!event) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (event) { | ||||
|       if (event === 'mouseenter') { | ||||
|         this.#element.addEventListener(event, () => { | ||||
|           this.#open(); | ||||
|         }); | ||||
|         this.#element.addEventListener('mouseleave', () => { | ||||
|           this.#close(); | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @description Закрывает список по клику вне элемента | ||||
|    * @method #closeSelectClick | ||||
|    */ | ||||
|   #closeSelectClick() { | ||||
|     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(); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @param {boolean} nativeSelectMode параметр отвечающий за добавления нативного селекта. | ||||
|    * @description Изменяет отображение селекта на мобильных устройствах | ||||
|    * @method #selectMode | ||||
|    */ | ||||
|   #selectMode(nativeSelectMode) { | ||||
|     let win = window.outerWidth; | ||||
|  | ||||
|     if (nativeSelectMode === true) { | ||||
|       const select = this.#element.querySelector('.cg-select'); | ||||
|       const list = this.#element.querySelector('.list'); | ||||
|       const nativeSelect = this.#element.querySelector('.nativeSelect'); | ||||
|  | ||||
|       if (win < 576) { | ||||
|         select.classList.add('displayHide'); | ||||
|         list.classList.add('displayHide'); | ||||
|         nativeSelect.classList.add('nativeSelectActive'); | ||||
|       } else if (win > 576) { | ||||
|         select.classList.remove('displayHide'); | ||||
|         list.classList.remove('displayHide'); | ||||
|         nativeSelect.classList.remove('nativeSelectActive'); | ||||
|         nativeSelect.classList.add('displayHide'); | ||||
|       } | ||||
|     } else { | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Приватный метод экземпляра класса DropDown | ||||
|    * @protected | ||||
|    * @param {boolean} listDisplayMode параметр отвечающий за отображение выбора в виде модального окна. | ||||
|    * @description Изменяет отображение листа с выбором в виде модального окна. | ||||
|    * @method #displayMode | ||||
|    */ | ||||
|   #displayMode(listDisplayMode) { | ||||
|     if (listDisplayMode === true) { | ||||
|       const modal = document.createElement('div'); | ||||
|       const body = document.querySelector('body'); | ||||
|       const list = this.#list; | ||||
|  | ||||
|       modal.appendChild(list); | ||||
|       this.#element.appendChild(modal); | ||||
|  | ||||
|       this.#element.addEventListener('click', () => { | ||||
|         modal.classList.toggle('modal'); | ||||
|         list.classList.toggle('listModal'); | ||||
|         body.classList.toggle('overflowHide'); | ||||
|       }); | ||||
|     } else { | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -3,7 +3,7 @@ import { | ||||
|   createInputSearch, | ||||
|   createNativeSelect, | ||||
|   createNativeSelectOption, | ||||
| } from './components/create-element/create-elementTs'; | ||||
| } from './components/create-element/create-element'; | ||||
| import { ICreateBreadCrumb } from './components/create-element/create-element.interface'; | ||||
| 
 | ||||
| import { | ||||
| @@ -15,12 +15,12 @@ import { | ||||
|   getSelectText, | ||||
|   nativeOptionMultiple, | ||||
|   nativeOptionOrdinary, | ||||
| } from './components/utils/utilsTs'; | ||||
| } from './components/utils/utils'; | ||||
| import { IDataItem, ISelectedItems } from './components/utils/urils.interface'; | ||||
| 
 | ||||
| import { ICgSelect, IStyle } from './interfaces/cg-select.interface'; | ||||
| import { IItems } from './interfaces/items.interface'; | ||||
| import { ru, en } from './language/languageTS'; | ||||
| import { ru, en } from './language/language'; | ||||
| import { ILanguage } from './interfaces/language.interface'; | ||||
| 
 | ||||
| import './main.scss'; | ||||
| @@ -235,7 +235,15 @@ export class CGSelect implements ICgSelect { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     createSelected; | ||||
|     if (this.lable) { | ||||
|       const lableItem = document.createElement('h1'); | ||||
|       const textLable = document.createTextNode(this.lable); | ||||
| 
 | ||||
|       lableItem.appendChild(textLable); | ||||
|       lableItem.classList.add('label'); | ||||
| 
 | ||||
|       this.element!.insertAdjacentElement('beforebegin', lableItem); | ||||
|     } | ||||
| 
 | ||||
|     items.forEach((dataItem: any, index: number) => { | ||||
|       let itemInputs: IDataItem = { | ||||
| @@ -454,16 +462,6 @@ export class CGSelect implements ICgSelect { | ||||
|       createSelected(this.element!, select, this.styles); | ||||
|     } | ||||
| 
 | ||||
|     if (this.lable) { | ||||
|       const lableItem = document.createElement('h1'); | ||||
|       const textLable = document.createTextNode(this.lable); | ||||
| 
 | ||||
|       lableItem.appendChild(textLable); | ||||
|       lableItem.classList.add('label'); | ||||
| 
 | ||||
|       this.element!.insertAdjacentElement('beforebegin', lableItem); | ||||
|     } | ||||
| 
 | ||||
|     if (this.styles) { | ||||
|       customStyles(this.element!, this.styles); | ||||
|     } | ||||
| @@ -1,121 +0,0 @@ | ||||
| import { customStylesFormat, nativeOptionMultiple } from './utils'; | ||||
| /** | ||||
|  * @module createBreadcrumb | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Метод который создает и отвечает за поведение chips | ||||
|  * @param {object} data объект в котором содержатся настройки и элементы селекта | ||||
|  * @param {string} title имя выбранного элемента для отрисовки chips | ||||
|  * @param {number} index индекс выбранного элемента для отрисовки chips | ||||
|  * @param {string} id уникальное id выбранного элемента | ||||
|  * @returns {HTMLElement} возвращает сформированный HTMLElement chips item | ||||
|  */ | ||||
| export function createBreadcrumb(data, title, index, id) { | ||||
|   const { element, option, indexes, selectedItems } = data; | ||||
|   const { placeholder, styles } = option; | ||||
|  | ||||
|   const selected = element.querySelector('.selected'); | ||||
|   const nativeOption = element.querySelectorAll('.nativeSelect__nativeOption'); | ||||
|  | ||||
|   const liChip = document.createElement('li'); | ||||
|   const textNode = document.createTextNode(title); | ||||
|   const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||||
|   const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|   const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|  | ||||
|   svgIcon.setAttribute('viewBox', '0 0 10 10'); | ||||
|   path1.setAttribute('d', 'M3,7 L7,3'); | ||||
|   path2.setAttribute('d', 'M3,3 L7,7'); | ||||
|   liChip.setAttribute('id', `tag-${index}-${id}`); | ||||
|  | ||||
|   svgIcon.classList.add('svg-icon'); | ||||
|  | ||||
|   svgIcon.appendChild(path1); | ||||
|   svgIcon.appendChild(path2); | ||||
|   liChip.appendChild(textNode); | ||||
|   liChip.appendChild(svgIcon); | ||||
|  | ||||
|   if (styles) { | ||||
|     const { chips } = styles; | ||||
|     customStylesFormat(chips, liChip); | ||||
|   } | ||||
|  | ||||
|   svgIcon.addEventListener('click', (event) => { | ||||
|     event.preventDefault(); | ||||
|     event.stopPropagation(); | ||||
|     nativeOptionMultiple(nativeOption, title, false); | ||||
|  | ||||
|     const deleteIcon = indexes.indexOf(index); | ||||
|     let checkBox = ''; | ||||
|  | ||||
|     indexes.splice(deleteIcon, 1); | ||||
|     selectedItems.splice(deleteIcon, 1); | ||||
|  | ||||
|     if (id) { | ||||
|       checkBox = document.getElementById(`chbox-${id}`); | ||||
|     } else { | ||||
|       checkBox = document.getElementById(`chbox-${index}`); | ||||
|     } | ||||
|  | ||||
|     checkBox.checked = false; | ||||
|     checkBox.parentElement.classList.remove('active'); | ||||
|  | ||||
|     if (!selectedItems.length) { | ||||
|       selected.innerText = placeholder; | ||||
|     } | ||||
|  | ||||
|     liChip.parentElement.removeChild(liChip); | ||||
|   }); | ||||
|  | ||||
|   return liChip; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Метод который создает нативный селект | ||||
|  * @returns {HTMLSelectElement} Возвращает созданный нативный селект | ||||
|  */ | ||||
| export function createNativeSelect() { | ||||
|   const nativeSelect = document.createElement('select'); | ||||
|  | ||||
|   nativeSelect.setAttribute('name', 'dataSelect'); | ||||
|   nativeSelect.classList.add('nativeSelect'); | ||||
|   return nativeSelect; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Метод который создает Options для нативного селекта | ||||
|  * @returns {HTMLOptionElement} Возвращает созданные Options нативного селекта | ||||
|  */ | ||||
| export function createNativeSelectOption() { | ||||
|   const nativeOption = document.createElement('option'); | ||||
|  | ||||
|   nativeOption.classList.add('nativeSelect__nativeOption'); | ||||
|   return nativeOption; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Метод который создает поиск элементов в селекте | ||||
|  * @param {string} random уникальное значение для input элемента. | ||||
|  * @param {string} lenguage текст на определенном языке переданный из файла language.js | ||||
|  * @returns {HTMLInputElement} Возвращает сформированный input елемент. | ||||
|  */ | ||||
| export function createInputSearch(random, lenguage) { | ||||
|   const inputSearch = document.createElement('input'); | ||||
|  | ||||
|   inputSearch.type = 'text'; | ||||
|   inputSearch.classList.add('inputSearch'); | ||||
|   inputSearch.setAttribute('id', `searchSelect-${random}`); | ||||
|  | ||||
|   if (lenguage) { | ||||
|     inputSearch.setAttribute('placeholder', `${lenguage}`); | ||||
|   } else { | ||||
|     inputSearch.setAttribute('placeholder', 'Search...'); | ||||
|   } | ||||
|  | ||||
|   inputSearch.addEventListener('click', (e) => { | ||||
|     e.preventDefault(); | ||||
|   }); | ||||
|  | ||||
|   return inputSearch; | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { customStylesFormat, nativeOptionMultiple } from '../utils/utilsTs'; | ||||
| import { customStylesFormat, nativeOptionMultiple } from '../utils/utils'; | ||||
| import { ICreateBreadCrumb } from './create-element.interface'; | ||||
| 
 | ||||
| /** | ||||
| @@ -1,227 +0,0 @@ | ||||
| /** | ||||
|  * Utils module | ||||
|  * @module Utils | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Создание кнопки выбора элементов | ||||
|  * @param {HTMLElement} element созданный экземпляр класса DropDown | ||||
|  * @param {string} content placeholer передаваемый из настроек селекта | ||||
|  * @param {object} styles не обязательный параметр. Объект в котором находяться настройки кастомизации частей селекта | ||||
|  */ | ||||
| export function createSelected(element, content, styles) { | ||||
|   if (content) { | ||||
|     element.innerHTML = ` | ||||
|       <div class="cg-select"> | ||||
|          <p class="selected">${content}</p> | ||||
|           <div class="caret"></div> | ||||
|        </div> | ||||
|       `; | ||||
|   } | ||||
|  | ||||
|   if (styles) { | ||||
|     customStyles(element, styles); | ||||
|  | ||||
|     element.innerHTML = ` | ||||
|       <div class="cg-select" style = "${styles}"> | ||||
|           <p class="selected" style = "${styles}">${content}</p> | ||||
|           <div class="caret" style = "${styles}"></div> | ||||
|       </div> | ||||
|     `; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Поиск и стилизация елементов полученных из styles экземпляра DropDown | ||||
|  * @param {HTMLElement} element созданный экземпляр класса DropDown | ||||
|  * @param {object} styles объект в котором находяться настройки кастомизации частей селекта | ||||
|  */ | ||||
| export function customStyles(element, styles) { | ||||
|   if (!styles) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   const { head, caret, placeholder, lable } = styles; | ||||
|  | ||||
|   const cgSelect = element.querySelector('.cg-select'); | ||||
|   const caretSelect = element.querySelector('.caret'); | ||||
|   const placeholderSelect = element.querySelector('.selected'); | ||||
|   const lableItem = element.parentElement.querySelector('h1.label'); | ||||
|  | ||||
|   customStylesFormat(head, cgSelect); | ||||
|   customStylesFormat(caret, caretSelect); | ||||
|   customStylesFormat(lable, lableItem); | ||||
|  | ||||
|   if (placeholderSelect) { | ||||
|     customStylesFormat(placeholder, placeholderSelect); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Универсальный метод для стилизации селекта | ||||
|  * @param {object} elemOption объект полученное из объекта styles у которого мы получаем ключ-значение стилей | ||||
|  * @param {HTMLElement} selector  HTMLElement подвергающиеся кастомизации | ||||
|  */ | ||||
| export function customStylesFormat(elemOption, selector) { | ||||
|   if (elemOption) { | ||||
|     Object.entries(elemOption).forEach(([key, value]) => { | ||||
|       selector.style[key] = value; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Проверка содержит ли item  указанные свойства, | ||||
|  * @param {object} item проверяемый на определенную структуру элемент | ||||
|  * @returns {boolean} возвращает true/false если item содержит указанные свойства | ||||
|  */ | ||||
| export function checkItemStruct(item) { | ||||
|   if (item && typeof item !== 'object') { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   return item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value'); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Вставка изначального текста селекта(до выбора) | ||||
|  * @param {object} data объект в котором находяться title селекта | ||||
|  * @param {HTMLElement} select елемент селекта, куда будет вставляться title | ||||
|  * @returns {HTMLElement} возвращает сформированный елемент селекта | ||||
|  */ | ||||
| export function getSelectText(data, select) { | ||||
|   const { placeholder, selected } = data; | ||||
|  | ||||
|   if (placeholder) { | ||||
|     select.innerText = placeholder; | ||||
|   } else if (selected) { | ||||
|     select.innerText = selected; | ||||
|   } else { | ||||
|     select.innerText = 'Select...'; | ||||
|   } | ||||
|   return select; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Преобразование каждого елемента полученного из поля Items; | ||||
|  * @param {object | string} dataItem полученный елемент переданный при создании селекта может быть как object/string | ||||
|  * @param {number} index индекс этого элемента | ||||
|  * @returns {object} возвращает сформированный объект | ||||
|  */ | ||||
| export function getFormatItem(dataItem, index) { | ||||
|   const random = Math.random().toString(36).substring(2, 10); | ||||
|   let item = {}; | ||||
|  | ||||
|   if (checkItemStruct(dataItem)) { | ||||
|     item = { | ||||
|       id: dataItem.id, | ||||
|       title: dataItem.title, | ||||
|       value: index, | ||||
|     }; | ||||
|   } else { | ||||
|     item = { | ||||
|       id: random, | ||||
|       title: dataItem, | ||||
|       value: index, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   return item; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Поведение нативного(одинарного) селекта при выборе кастомного | ||||
|  * @param {NodeList} element NodeList нативного селекта | ||||
|  * @param {object} item выбранный элемент в кастомном селекте | ||||
|  */ | ||||
| export function nativeOptionOrdinary(element, item) { | ||||
|   element.forEach((option) => { | ||||
|     option.removeAttribute('selected'); | ||||
|     if (option.textContent === item) { | ||||
|       option.setAttribute('selected', 'selected'); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Поведение нативного(Multiple) селекта при выборе в кастомном | ||||
|  * @param {NodeList} element NodeList нативного селекта | ||||
|  * @param {object} item выбранный элемент в кастомном селекте | ||||
|  * @param {boolean} condition специальный флаг при котором добавляются/убераются атрибуты у нативного селекта | ||||
|  */ | ||||
| export function nativeOptionMultiple(element, item, condition) { | ||||
|   element.forEach((option) => { | ||||
|     if (condition == true) { | ||||
|       if (option.textContent === item) { | ||||
|         option.setAttribute('selected', 'selected'); | ||||
|       } | ||||
|     } else if (condition == false) { | ||||
|       if (option.textContent === item) { | ||||
|         option.removeAttribute('selected'); | ||||
|       } | ||||
|     } else { | ||||
|       return; | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Создание кнопки отчиски селекта, при единичном выборе. | ||||
|  * @param {HTMLElement} select место в селекте которое будет переназначено на ''. | ||||
|  * @param {HTMLElement} element экземпляр класса DropDown. | ||||
|  * @param {object} dataSelectText текст который отрисовывается в селекте. | ||||
|  */ | ||||
| export function clearSelect(select, element, dataSelectText) { | ||||
|   const { selectedItems, indexes, darkTheme, multiselectTag } = dataSelectText; | ||||
|  | ||||
|   const options = element.querySelectorAll('.list__item'); | ||||
|   const ulMultiSelect = element.querySelector('.multiselect-tag'); | ||||
|   const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||||
|   const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|   const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|   const checkBox = element.querySelectorAll('li input'); | ||||
|  | ||||
|   svgIcon.setAttribute('viewBox', '0 0 10 10'); | ||||
|   path1.setAttribute('d', 'M2,8 L8,2'); | ||||
|   path2.setAttribute('d', 'M2,2 L8,8'); | ||||
|   svgIcon.appendChild(path1); | ||||
|   svgIcon.appendChild(path2); | ||||
|  | ||||
|   if (multiselectTag && multiselectTag == true) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (darkTheme === true || !darkTheme) { | ||||
|     path1.classList.add('pathWhite'); | ||||
|     path2.classList.add('pathWhite'); | ||||
|   } | ||||
|  | ||||
|   if (darkTheme === false) { | ||||
|     path1.classList.add('pathBlack'); | ||||
|     path2.classList.add('pathBlack'); | ||||
|   } | ||||
|  | ||||
|   svgIcon.classList.add('svg-icon'); | ||||
|   svgIcon.classList.add('svg-clear'); | ||||
|  | ||||
|   select.appendChild(svgIcon); | ||||
|  | ||||
|   svgIcon.addEventListener('click', () => { | ||||
|     select.innerText = ''; | ||||
|  | ||||
|     if (Array.isArray(selectedItems)) { | ||||
|       selectedItems.splice(0); | ||||
|       indexes.splice(0); | ||||
|     } | ||||
|  | ||||
|     checkBox.forEach((item) => { | ||||
|       item.checked = false; | ||||
|     }); | ||||
|  | ||||
|     getSelectText(dataSelectText, select); | ||||
|  | ||||
|     options.forEach((option) => { | ||||
|       option.classList.remove('active'); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| @@ -86,7 +86,8 @@ export function createSelected(element: Element, content?: string, styles?: ISty | ||||
|   if (content) { | ||||
|     const text = document.createTextNode(content); | ||||
|     selected.appendChild(text); | ||||
|     element?.appendChild(select); | ||||
|     element.innerHTML = ''; | ||||
|     element?.insertAdjacentElement('afterbegin', select); | ||||
|   } else if (styles) { | ||||
|     customStyles(element!, styles); | ||||
|     select.setAttribute('style', `${styles}`); | ||||
| @@ -105,7 +106,7 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex | ||||
|   const { selectedItems, indexes, darkTheme, multiselectTag } = dataSelectText; | ||||
| 
 | ||||
|   const options = element.querySelectorAll('.list__item'); | ||||
|   const ulMultiSelect = element.querySelector('.multiselect-tag'); | ||||
|   const nativeOption = element!.querySelectorAll('.nativeSelect__nativeOption'); | ||||
|   const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); | ||||
|   const path1 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
|   const path2 = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | ||||
| @@ -139,6 +140,10 @@ export function clearSelect(select: HTMLElement, element: Element, dataSelectTex | ||||
|   svgIcon.addEventListener('click', () => { | ||||
|     select!.innerText = ''; | ||||
| 
 | ||||
|     nativeOption.forEach((option) => { | ||||
|       option.removeAttribute('selected'); | ||||
|     }); | ||||
| 
 | ||||
|     if (Array.isArray(selectedItems)) { | ||||
|       selectedItems!.splice(0); | ||||
|       indexes!.splice(0); | ||||
| @@ -1,11 +0,0 @@ | ||||
| export const ru = { | ||||
|   selectPlaceholder: 'Выберите элемент...', | ||||
|   placeholder: 'Поиск...', | ||||
|   textInListSearch: 'Совпадений нет...', | ||||
| }; | ||||
|  | ||||
| export const en = { | ||||
|   selectPlaceholder: 'Select element...', | ||||
|   placeholder: 'Search...', | ||||
|   textInListSearch: 'No matches...', | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user