From d8b07d2e6c3f575d3e569574c57018a25eb695eb Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Thu, 29 Sep 2022 20:21:14 +0300 Subject: [PATCH 1/5] Added new branch and bulding multiselect 35-45% --- src/cg-dropdown.js | 103 ++++++++++++++++++++++++++++---------------- src/index.html | 2 +- src/index.js | 28 +++--------- src/style/main.scss | 13 ++++++ 4 files changed, 84 insertions(+), 62 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index be9ad98..914c878 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -105,7 +105,7 @@ export class DropDown { } #render(select) { - const { items, styles, url } = this.#options; + const { items, styles, url, multiselect } = this.#options; if (select || (select && styles)) { this.#initSelected(select); @@ -122,42 +122,51 @@ export class DropDown { ul.classList.add('list'); - if (ul) { - if (list) { - Object.entries(list).forEach(([key, value]) => { - ul.style[key] = value; - }); - } + if (ul && list) { + Object.entries(list).forEach(([key, value]) => { + ul.style[key] = value; + }); } + this.#element.appendChild(ul); } else { ul.classList.add('list'); this.#element.appendChild(ul); } - if (!items) { - if (url) { - this.#renderUrl(); - } - } else { - items.map((item) => { - let li = document.createElement('li'); - - if (typeof item == 'object') { - const text = document.createTextNode(item.title); - - li.classList.add('list__item'); - li.appendChild(text); - } else { - const text = document.createTextNode(item); - - li.classList.add('list__item'); - li.appendChild(text); - } - - ul.appendChild(li); - }); + if (!items && url) { + this.#renderUrl(); + return; } + + items.forEach((item) => { + const li = document.createElement('li'); + let text = ''; + + li.classList.add('list__item'); + + if (item && typeof item === 'object' && item.title) { + text = item.title; + } else { + text = item; + } + + if (multiselect) { + const checkBox = document.createElement('input'); + + checkBox.type = 'checkbox'; + checkBox.addEventListener('click', (event) => { + event.stopPropagation(); + }); + + li.appendChild(checkBox); + } + + let textNode = document.createTextNode(text); + + li.appendChild(textNode); + ul.appendChild(li); + }); } async #renderUrl() { @@ -172,7 +181,6 @@ export class DropDown { } const response = await fetch(url); - const data = await response.json(); //ToDO: fix title(item.title!) @@ -182,11 +190,10 @@ export class DropDown { title: item.name, value: index, }; - const ul = this.#element.querySelector('.list'); - const li = document.createElement('li'); const text = document.createTextNode(items.title); + li.classList.add('list__item'); li.appendChild(text); ul.appendChild(li); @@ -207,17 +214,30 @@ export class DropDown { } #selectItem() { + const { multiselect } = this.#options; + const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); options.forEach((option) => { - option.addEventListener('click', () => { - selected.innerText = option.innerText; + option.addEventListener('click', (event) => { + if (multiselect) { + event.stopPropagation(); + option.classList.toggle('active'); - options.forEach((option) => { - option.classList.remove('active'); - }); - option.classList.add('active'); + const checkBox = option.querySelector('input[type="checkbox"]'); + + if (checkBox) { + checkBox.checked = !checkBox.checked; + } + } else { + selected.innerText = option.innerText; + options.forEach((option) => { + option.classList.remove('active'); + }); + option.classList.add('active'); + // this.getValue(); + } }); }); } @@ -296,4 +316,11 @@ export class DropDown { `; } } + + // getValue() { + // const selected = this.#element.querySelector('.selected'); + // const value = selected.innerText; + // console.log(value); + // return value; + // } } diff --git a/src/index.html b/src/index.html index 2856148..b0acd6d 100644 --- a/src/index.html +++ b/src/index.html @@ -13,7 +13,7 @@
-
+
diff --git a/src/index.js b/src/index.js index f8ef3e8..9a8edcd 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ const dropdown = new DropDown({ selector: '.cg-dropdown', placeholder: 'Выберите авто', items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'max'], + multiselect: true, }); dropdown.addItem('ZAZ'); @@ -11,32 +12,13 @@ dropdown.addItem('LADA'); const dropdown2 = new DropDown({ selector: '.cg-dropdown2', - placeholder: 'Выберите авто', + placeholder: 'SELECT CAR', items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'Kamaz'], - event: 'mouseenter', - styles: { - head: { - background: 'red', - color: 'black', - width: '400px', - }, - placeholder: { - color: 'grey', - }, - caret: { - 'border-top': '6px solid black', - }, - list: { - background: 'red', - color: 'black', - width: '412px', - }, - }, }); - -dropdown2.addItem('LADA'); - +// let a = dropdown2.getValue(); +// console.log(a); //ToDo: paste the desired url; + const dropdown3 = new DropDown({ selector: '.cg-dropdown3', placeholder: 'URL', diff --git a/src/style/main.scss b/src/style/main.scss index 634b0bc..3bdca06 100644 --- a/src/style/main.scss +++ b/src/style/main.scss @@ -105,3 +105,16 @@ body { ::-webkit-scrollbar-thumb { background-color: #4d4d4d; } + +.multiselect { + height: 20px; + + display: flex; + align-items: center; + + li { + color: red; + border: 1px solid #4d4d4d; + } + z-index: 999; +} From 751e428e91b4a24bcedc289ddbe76408316edcfa Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 30 Sep 2022 16:22:14 +0300 Subject: [PATCH 2/5] Added accessor get for value. Added multiselect option --- src/cg-dropdown.js | 57 +++++++++++++++++++++++++++++++++++++--------- src/index.js | 22 +++++++++++++++++- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index 914c878..218317e 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -4,6 +4,19 @@ export class DropDown { #options; #caret; #items; + #value; + + get value() { + const { multiselect } = this.#options; + + if (multiselect) { + return this.#items.filter((item, index) => { + return this.#value.indexOf(index) !== -1; + }); + } + + return this.#value; + } constructor(options = {}) { this.#init(options); @@ -60,8 +73,12 @@ export class DropDown { this.#list = this.#element.querySelector('.list'); this.#caret = this.#element.querySelector('.caret'); - const { items } = this.#options; + const { items, multiselect } = this.#options; this.#items = items; + + if (multiselect) { + this.#value = []; + } } #initSelected(select) { @@ -145,7 +162,7 @@ export class DropDown { li.classList.add('list__item'); - if (item && typeof item === 'object' && item.title) { + if (this.#checkItemStruct(item)) { text = item.title; } else { text = item; @@ -219,8 +236,10 @@ export class DropDown { const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); - options.forEach((option) => { + options.forEach((option, index) => { option.addEventListener('click', (event) => { + const item = this.#items[index]; + if (multiselect) { event.stopPropagation(); option.classList.toggle('active'); @@ -229,14 +248,27 @@ export class DropDown { if (checkBox) { checkBox.checked = !checkBox.checked; + + const indexValue = this.#value.indexOf(index); + if (indexValue === -1) { + this.#value.push(index); + } else { + this.#value.splice(indexValue, 1); + } } } else { - selected.innerText = option.innerText; + if (this.#checkItemStruct(item)) { + selected.innerText = item.title; + } else { + selected.innerText = item; + } + + this.#value = item; + options.forEach((option) => { option.classList.remove('active'); }); option.classList.add('active'); - // this.getValue(); } }); }); @@ -317,10 +349,13 @@ export class DropDown { } } - // getValue() { - // const selected = this.#element.querySelector('.selected'); - // const value = selected.innerText; - // console.log(value); - // return value; - // } + #checkItemStruct(item) { + if (item && typeof item !== 'object') { + return false; + } + + return ( + item.hasOwnProperty('id') && item.hasOwnProperty('title') && item.hasOwnProperty('value') + ); + } } diff --git a/src/index.js b/src/index.js index 9a8edcd..0ffb454 100644 --- a/src/index.js +++ b/src/index.js @@ -13,8 +13,28 @@ dropdown.addItem('LADA'); const dropdown2 = new DropDown({ selector: '.cg-dropdown2', placeholder: 'SELECT CAR', - items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'Kamaz'], + items: [ + { + id: 'addaw21', + title: 'BMW', + value: '1', + }, + { + id: '2414q', + title: 'Opel', + value: '2', + }, + { + id: '24qwds', + title: 'Kamaz', + value: '3', + }, + ], }); + +setTimeout(() => { + console.log(dropdown.value); +}, 10000); // let a = dropdown2.getValue(); // console.log(a); //ToDo: paste the desired url; From 1cc688a50f7a41292aff50a5ea1b386787a3ea43 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Fri, 30 Sep 2022 22:14:39 +0300 Subject: [PATCH 3/5] Multiselect refactoring --- src/cg-dropdown.js | 65 +++++++++++++++++++++++++++------------------ src/index.js | 5 ++++ src/style/main.scss | 4 +++ 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index 218317e..e5527eb 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -5,17 +5,14 @@ export class DropDown { #caret; #items; #value; + #indexes = []; get value() { - const { multiselect } = this.#options; + return this.#value ?? null; + } - if (multiselect) { - return this.#items.filter((item, index) => { - return this.#value.indexOf(index) !== -1; - }); - } - - return this.#value; + get indexes() { + return this.#indexes ?? []; } constructor(options = {}) { @@ -66,7 +63,6 @@ export class DropDown { this.#element = elem; this.#element.addEventListener('click', () => { - this.#selectItem(); this.#open(); }); @@ -153,6 +149,7 @@ export class DropDown { if (!items && url) { this.#renderUrl(); + return; } @@ -170,12 +167,7 @@ export class DropDown { if (multiselect) { const checkBox = document.createElement('input'); - checkBox.type = 'checkbox'; - checkBox.addEventListener('click', (event) => { - event.stopPropagation(); - }); - li.appendChild(checkBox); } @@ -184,6 +176,8 @@ export class DropDown { li.appendChild(textNode); ul.appendChild(li); }); + + this.#addOptionsBehaviour(); } async #renderUrl() { @@ -201,20 +195,26 @@ export class DropDown { const data = await response.json(); //ToDO: fix title(item.title!) - data.forEach((item, index) => { - const items = { - id: item.id, - title: item.name, + this.#items = []; + + data.forEach((dataItem, index) => { + const item = { + id: dataItem.id, + title: dataItem.name, value: index, }; const ul = this.#element.querySelector('.list'); const li = document.createElement('li'); - const text = document.createTextNode(items.title); + const text = document.createTextNode(item.title); li.classList.add('list__item'); li.appendChild(text); ul.appendChild(li); + + this.#items.push(item); }); + + this.#addOptionsBehaviour(); } #open() { @@ -230,8 +230,8 @@ export class DropDown { this.#caret.classList.remove('caret_rotate'); } - #selectItem() { - const { multiselect } = this.#options; + #addOptionsBehaviour() { + const { multiselect, placeholder } = this.#options; const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); @@ -247,13 +247,26 @@ export class DropDown { const checkBox = option.querySelector('input[type="checkbox"]'); if (checkBox) { - checkBox.checked = !checkBox.checked; + if (!(event.target instanceof HTMLInputElement)) { + checkBox.checked = !checkBox.checked; + } - const indexValue = this.#value.indexOf(index); - if (indexValue === -1) { - this.#value.push(index); + const checkIndex = this.#indexes.indexOf(index); + + if (checkIndex === -1) { + this.#indexes.push(index); + this.#value.push(item); + selected.innerText = this.#value; + return; + } + + this.#indexes.splice(checkIndex, 1); + this.#value.splice(checkIndex, 1); + + if (!this.#value.length) { + selected.innerText = placeholder; } else { - this.#value.splice(indexValue, 1); + selected.innerText = this.#value; } } } else { diff --git a/src/index.js b/src/index.js index 0ffb454..90c61ed 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,8 @@ const dropdown = new DropDown({ placeholder: 'Выберите авто', items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'max'], multiselect: true, + itemSelected: (item, index) => {}, + itemRemoved: (item, index) => {}, }); dropdown.addItem('ZAZ'); @@ -35,6 +37,9 @@ const dropdown2 = new DropDown({ setTimeout(() => { console.log(dropdown.value); }, 10000); +setTimeout(() => { + console.log(dropdown.indexes); +}, 10000); // let a = dropdown2.getValue(); // console.log(a); //ToDo: paste the desired url; diff --git a/src/style/main.scss b/src/style/main.scss index 3bdca06..530fade 100644 --- a/src/style/main.scss +++ b/src/style/main.scss @@ -118,3 +118,7 @@ body { } z-index: 999; } + +input[type='checkbox'] { + cursor: pointer; +} From 72066a9c88e6951809dcaf87ff90df43dea0eb59 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Mon, 3 Oct 2022 21:43:22 +0300 Subject: [PATCH 4/5] Working as multiselectTag --- src/cg-dropdown.js | 44 +++++++++++++++++++++++++++++++++++++++++--- src/index.js | 24 +++++++++++++++++------- src/style/main.scss | 17 +++++++++++++++++ 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index e5527eb..5eeee57 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -207,6 +207,10 @@ export class DropDown { const li = document.createElement('li'); const text = document.createTextNode(item.title); + const checkBox = document.createElement('input'); + checkBox.type = 'checkbox'; + li.appendChild(checkBox); + li.classList.add('list__item'); li.appendChild(text); ul.appendChild(li); @@ -231,15 +235,34 @@ export class DropDown { } #addOptionsBehaviour() { - const { multiselect, placeholder } = this.#options; + const { multiselect, placeholder, multiselectTag } = this.#options; const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); + const ul = document.createElement('ul'); + options.forEach((option, index) => { option.addEventListener('click', (event) => { const item = this.#items[index]; + const li = document.createElement('li'); + const btn = document.createElement('button'); + const text = document.createTextNode('X'); + + // let textLi = document.createTextNode(item); + // t.toString(); + // console.log(textLi); + + btn.appendChild(text); + btn.addEventListener('click', () => { + console.log('aaaa'); + ul.removeChild(li); + }); + + ul.classList.add('multiselectTag'); + console.log(ul); + if (multiselect) { event.stopPropagation(); option.classList.toggle('active'); @@ -255,8 +278,23 @@ export class DropDown { if (checkIndex === -1) { this.#indexes.push(index); - this.#value.push(item); - selected.innerText = this.#value; + + if (this.#checkItemStruct(item)) { + this.#value.push(item.title); + } else { + let textLi = document.createTextNode(item); + li.appendChild(textLi); + li.appendChild(btn); + ul.appendChild(li); + + this.#value.push(item); + } + + // selected.innerText = this.#value; + + selected.innerText = ''; + selected.appendChild(ul); + return; } diff --git a/src/index.js b/src/index.js index 90c61ed..4ab2beb 100644 --- a/src/index.js +++ b/src/index.js @@ -5,8 +5,7 @@ const dropdown = new DropDown({ placeholder: 'Выберите авто', items: ['BMW', 'Opel', 'Mersedes', 'MAN', 'max'], multiselect: true, - itemSelected: (item, index) => {}, - itemRemoved: (item, index) => {}, + multiselectTag: true, }); dropdown.addItem('ZAZ'); @@ -28,26 +27,37 @@ const dropdown2 = new DropDown({ }, { id: '24qwds', - title: 'Kamaz', + title: 'Kamaz 258', value: '3', }, + { + id: '28wds', + title: 'MAN', + value: '4', + }, + { + id: '28qwds', + title: 'BOOT', + value: '5', + }, ], + multiselect: true, }); setTimeout(() => { - console.log(dropdown.value); + console.log(dropdown2.value); }, 10000); setTimeout(() => { - console.log(dropdown.indexes); + console.log(dropdown2.indexes); }, 10000); -// let a = dropdown2.getValue(); -// console.log(a); + //ToDo: paste the desired url; const dropdown3 = new DropDown({ selector: '.cg-dropdown3', placeholder: 'URL', url: 'http://jsonplaceholder.typicode.com/users', + multiselect: true, }); // const dropdown3 = new DropDown({ diff --git a/src/style/main.scss b/src/style/main.scss index 530fade..0742c1f 100644 --- a/src/style/main.scss +++ b/src/style/main.scss @@ -21,17 +21,26 @@ body { .cg-select { padding: 14px; min-width: 200px; + max-width: 200px; height: 30px; color: #fff; display: flex; justify-content: space-between; align-items: center; + overflow: hidden; + text-overflow: ellipsis; background: #2a2f3b; cursor: pointer; border-radius: 5px; transition: 0.5s; + .selected { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + &:hover { transition: 0.5s; background: #394050; @@ -119,6 +128,14 @@ body { z-index: 999; } +.multiselectTag { + display: flex; + text-decoration: none; + flex-direction: row; + height: 15px; + list-style-type: none; +} + input[type='checkbox'] { cursor: pointer; } From af54b890a7e4d8795e4a9e49145bb9b0707f22e3 Mon Sep 17 00:00:00 2001 From: MaxOvs Date: Tue, 4 Oct 2022 21:53:31 +0300 Subject: [PATCH 5/5] Multiselect in working, but requires refactor! --- src/cg-dropdown.js | 53 +++++++++++++++++++++++----------------------- src/index.js | 4 ++-- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/cg-dropdown.js b/src/cg-dropdown.js index 5eeee57..a858828 100644 --- a/src/cg-dropdown.js +++ b/src/cg-dropdown.js @@ -240,29 +240,14 @@ export class DropDown { const options = this.#element.querySelectorAll('.list__item'); const selected = this.#element.querySelector('.selected'); - const ul = document.createElement('ul'); + // const ul = document.createElement('ul'); + + // ul.classList.add('multiselectTag'); options.forEach((option, index) => { option.addEventListener('click', (event) => { const item = this.#items[index]; - const li = document.createElement('li'); - const btn = document.createElement('button'); - const text = document.createTextNode('X'); - - // let textLi = document.createTextNode(item); - // t.toString(); - // console.log(textLi); - - btn.appendChild(text); - btn.addEventListener('click', () => { - console.log('aaaa'); - ul.removeChild(li); - }); - - ul.classList.add('multiselectTag'); - console.log(ul); - if (multiselect) { event.stopPropagation(); option.classList.toggle('active'); @@ -276,24 +261,26 @@ export class DropDown { const checkIndex = this.#indexes.indexOf(index); + let templete = ''; if (checkIndex === -1) { this.#indexes.push(index); if (this.#checkItemStruct(item)) { this.#value.push(item.title); } else { - let textLi = document.createTextNode(item); - li.appendChild(textLi); - li.appendChild(btn); - ul.appendChild(li); - this.#value.push(item); } - // selected.innerText = this.#value; + //TODO refactoring code!!!! + if (multiselectTag) { + for (let i = 0; i < this.#value.length; i++) { + templete += `
  • ${this.#value[i]}
  • `; + } - selected.innerText = ''; - selected.appendChild(ul); + selected.innerHTML = `
      ${templete}
    `; + } else { + selected.innerText = this.#value; + } return; } @@ -301,10 +288,22 @@ export class DropDown { this.#indexes.splice(checkIndex, 1); this.#value.splice(checkIndex, 1); + if (multiselectTag) { + for (let i = 0; i < this.#value.length; i++) { + templete += `
  • ${this.#value[i]}
  • `; + } + + selected.innerHTML = `
      ${templete}
    `; + } + if (!this.#value.length) { selected.innerText = placeholder; } else { - selected.innerText = this.#value; + if (multiselectTag) { + selected.innerHTML = `
      ${templete}
    `; + } else { + selected.innerText = this.#value; + } } } } else { diff --git a/src/index.js b/src/index.js index 4ab2beb..eaa4547 100644 --- a/src/index.js +++ b/src/index.js @@ -45,10 +45,10 @@ const dropdown2 = new DropDown({ }); setTimeout(() => { - console.log(dropdown2.value); + console.log(dropdown.value); }, 10000); setTimeout(() => { - console.log(dropdown2.indexes); + console.log(dropdown.indexes); }, 10000); //ToDo: paste the desired url;