Skip to content

Commit 93316c5

Browse files
committed
[PRAC/cont] Decompose "dynamic" function
Organiz moving/out child func's from createAddModalContactsElement(). Worth noting: - that/thus.. improved readability, code structuring (without overloading a single function). core: B-3 / JS-BL
1 parent c765839 commit 93316c5

File tree

1 file changed

+159
-142
lines changed
  • core-courses/3-js-basic-level/practicum-js-basic-level/sb-crm-client/js

1 file changed

+159
-142
lines changed

core-courses/3-js-basic-level/practicum-js-basic-level/sb-crm-client/js/index.js

Lines changed: 159 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@
579579

580580
// исключение недопустимых символов (вообще)
581581
target.value = target.value.replace(
582-
/[=+,!?%#$^&:{}()<>|"'*/\\]/g,
582+
/[=+,`~!?%#$^&:{}()<>|"'*/\\]/g,
583583
''
584584
);
585585

@@ -1102,7 +1102,7 @@
11021102
// остановка мониторинга (если более не требуется)
11031103
// observer.disconnect();
11041104

1105-
// ** динамическое добавление строки контактов в add-модальном окне (по нажатию "Добавить контакт" кнопки, объёмная логика.. ряд "внутренних" функций)
1105+
// ** динамическое добавление строки контактов в add-модальном окне (по нажатию "Добавить контакт" кнопки)
11061106
const addModalContactsArr = [];
11071107

11081108
function createAddModalContactsElement() {
@@ -1326,86 +1326,32 @@
13261326
}
13271327
});
13281328

1329-
// замена/обновление содержимого/контента кнопки, так и через TAB/Enter (согласно значений li/вариантов)
1329+
// замена/обновление содержимого/контента кнопки, так.. и через TAB/Enter (согласно значений li/вариантов)
13301330
addModalContactList.addEventListener('click', (event) => {
13311331
if (event.target.tagName === 'LI') {
1332-
getContactDropSelection(event.target); // отработка выбора
1332+
getContactDropSelection(
1333+
event.target,
1334+
addModalContactDropBtn,
1335+
addModalContactList,
1336+
addModalContactHiddenInput,
1337+
addModalContactInput
1338+
); // отработка выбора
13331339
}
13341340
});
13351341

13361342
addModalContactList.addEventListener('keydown', (event) => {
13371343
if (event.target.tagName === 'LI' && event.key === 'Enter') {
13381344
event.preventDefault(); // исключение непредвиденных событий/поведения
1339-
getContactDropSelection(event.target); // отработка выбора
1345+
getContactDropSelection(
1346+
event.target,
1347+
addModalContactDropBtn,
1348+
addModalContactList,
1349+
addModalContactHiddenInput,
1350+
addModalContactInput
1351+
); // отработка выбора
13401352
}
13411353
});
13421354

1343-
function getContactDropSelection(target) {
1344-
const selectedItemValue = target.getAttribute('data-value');
1345-
const previousItemValue = addModalContactHiddenInput.value; // фиксация скрытого значения
1346-
1347-
// обработка смены/типа контакта (если/с одного "вдруг" на другой решили)
1348-
if (
1349-
!changeContactRowType(
1350-
addModalContactInput,
1351-
selectedItemValue,
1352-
previousItemValue
1353-
)
1354-
) {
1355-
return; // исключение корректировки, если/в confirm отмена
1356-
}
1357-
1358-
addModalContactDropBtn.textContent = target.textContent;
1359-
addModalContactHiddenInput.value = selectedItemValue; // обновление данных в "скрытом" input (для последующей отправки на сервер)
1360-
1361-
target.style.display = 'none'; // скрытие li/варианта в выпадающем списке (т.е. после выбора, отображения в drop-btn)
1362-
1363-
// отображение/снова li/варианта (т.е. до этого скрытого)
1364-
if (previousItemValue) {
1365-
const previousItem = addModalContactList.querySelector(
1366-
`[data-value="${previousItemValue}"]`
1367-
);
1368-
if (previousItem) {
1369-
previousItem.style.display = ''; // сброс display: none;
1370-
}
1371-
}
1372-
1373-
updateRowInputType(addModalContactInput, selectedItemValue); // обновление атрибута/значения "type" у/для инпута (кому возможно)
1374-
updateDropItemPaddings(addModalContactList); // обновление/изменение отступов для li/вариантов выпадающего списка (для первого и последнего элементов)
1375-
closeBtnDropdown(); // закрытие выпадающего списка
1376-
addModalContactInput.focus(); // перевод фокуса на соседний инпут (после выбора в выпадающем списке)
1377-
}
1378-
1379-
function updateDropItemPaddings(dropList) {
1380-
Array.from(dropList.children).forEach((item) => {
1381-
item.classList.remove('first-visible', 'last-visible'); // изначальная очистка от дополнительных классов
1382-
});
1383-
1384-
// фиксация li/вариантов находящихся "сейчас" в выпадающем списке
1385-
const visibleDropItems = Array.from(dropList.children).filter(
1386-
(item) => item.style.display !== 'none'
1387-
);
1388-
1389-
// добавление отступов (для первого/последнего элементов списка)
1390-
if (visibleDropItems.length > 0) {
1391-
const firstVisibleItem = visibleDropItems[0];
1392-
const lastVisibleItem = visibleDropItems[visibleDropItems.length - 1];
1393-
firstVisibleItem.classList.add('first-visible');
1394-
lastVisibleItem.classList.add('last-visible');
1395-
}
1396-
}
1397-
1398-
function closeBtnDropdown() {
1399-
const openDropdownBtn = document.querySelector('.drop-open'); // фиксация "открывающей" drop-кнопки
1400-
1401-
if (openDropdownBtn) {
1402-
const dropdownList = openDropdownBtn.nextElementSibling; // фиксация выпадающего списка
1403-
openDropdownBtn.classList.remove('arrow-rotate', 'drop-open'); // возврат направления стрелки, удаление "открывающего" класса
1404-
dropdownList.classList.add('d-none'); // скрытие выпадающего списка
1405-
openDropdownBtn.blur(); // снятие фокуса с кнопки (после выбора)
1406-
}
1407-
}
1408-
14091355
// автоматическое закрытие/скрытие развёрнутого выпадающего drop-списка (при работе НЕ с ним)
14101356
document.addEventListener('click', (event) => {
14111357
const openDropdownBtn = document.querySelector('.drop-open');
@@ -1463,7 +1409,92 @@
14631409
createAddModalContactsElement();
14641410
});
14651411

1466-
// ** организация замены выбора/типа row-контакта, после начала/внесения данных в инпут (вывод уточняющего сообщения)
1412+
// ** обработка выбора/типа модального row-контакта из li/вариантов выпадающего drop-списка (замена/обновление содержимого/контента drop-кнопки, ряд других действий)
1413+
function getContactDropSelection(
1414+
target,
1415+
dropBtn,
1416+
contactList,
1417+
hiddenInput,
1418+
contactInput
1419+
) {
1420+
const selectedItemValue = target.getAttribute('data-value');
1421+
const previousItemValue = hiddenInput.value; // фиксация скрытого значения
1422+
1423+
// обработка смены/типа контакта (если/с одного "вдруг" на другой решили)
1424+
if (
1425+
!changeContactRowType(contactInput, selectedItemValue, previousItemValue)
1426+
) {
1427+
return; // исключение корректировки, если/в confirm отмена
1428+
}
1429+
1430+
dropBtn.textContent = target.textContent;
1431+
hiddenInput.value = selectedItemValue; // обновление данных в "скрытом" input (для последующей отправки на сервер)
1432+
1433+
target.style.display = 'none'; // скрытие li/варианта в выпадающем списке (т.е. после выбора, отображения в drop-btn)
1434+
1435+
// отображение/снова li/варианта (т.е. до этого скрытого)
1436+
if (previousItemValue) {
1437+
const previousItem = contactList.querySelector(
1438+
`[data-value="${previousItemValue}"]`
1439+
);
1440+
if (previousItem) {
1441+
previousItem.style.display = ''; // сброс display: none;
1442+
}
1443+
}
1444+
1445+
updateRowInputType(contactInput, selectedItemValue); // обновление атрибута/значения "type" у/для инпута (кому возможно)
1446+
updateDropItemPaddings(contactList); // обновление/изменение отступов для li/вариантов выпадающего списка (для первого и последнего элементов)
1447+
closeBtnDropdown(); // закрытие выпадающего списка
1448+
contactInput.focus(); // перевод фокуса на соседний инпут (после выбора в выпадающем списке)
1449+
}
1450+
1451+
// ** обновление атрибута/значения "type" у/для модального row-инпута (кому возможно, после выбора)
1452+
function updateRowInputType(input, contactType) {
1453+
// объект для сопоставления (кому заменять, на какое значение)
1454+
const typeMapping = {
1455+
phone: 'tel',
1456+
'extra-phone': 'tel',
1457+
email: 'email',
1458+
};
1459+
1460+
// корректировка атрибута/значения "type" (или будет text)
1461+
const newType = typeMapping[contactType] || 'text';
1462+
input.setAttribute('type', newType);
1463+
}
1464+
1465+
// ** обновление/изменение отступов для модальных li/вариантов выпадающего row-списка (для первого и последнего элементов)
1466+
function updateDropItemPaddings(dropList) {
1467+
Array.from(dropList.children).forEach((item) => {
1468+
item.classList.remove('first-visible', 'last-visible'); // изначальная очистка от дополнительных классов
1469+
});
1470+
1471+
// фиксация li/вариантов находящихся "сейчас" в выпадающем списке
1472+
const visibleDropItems = Array.from(dropList.children).filter(
1473+
(item) => item.style.display !== 'none'
1474+
);
1475+
1476+
// добавление отступов (для первого/последнего элементов списка)
1477+
if (visibleDropItems.length > 0) {
1478+
const firstVisibleItem = visibleDropItems[0];
1479+
const lastVisibleItem = visibleDropItems[visibleDropItems.length - 1];
1480+
firstVisibleItem.classList.add('first-visible');
1481+
lastVisibleItem.classList.add('last-visible');
1482+
}
1483+
}
1484+
1485+
// ** организация закрытия/скрытия выпадающего row-списка в модальном окне (снятие фокуса)
1486+
function closeBtnDropdown() {
1487+
const openDropdownBtn = document.querySelector('.drop-open'); // фиксация "открывающей" drop-кнопки
1488+
1489+
if (openDropdownBtn) {
1490+
const dropdownList = openDropdownBtn.nextElementSibling; // фиксация выпадающего списка
1491+
openDropdownBtn.classList.remove('arrow-rotate', 'drop-open'); // возврат направления стрелки, удаление "открывающего" класса
1492+
dropdownList.classList.add('d-none'); // скрытие выпадающего списка
1493+
openDropdownBtn.blur(); // снятие фокуса с кнопки (после выбора)
1494+
}
1495+
}
1496+
1497+
// ** организация замены выбора/типа модального row-контакта, после начала/внесения данных в инпут (вывод уточняющего сообщения)
14671498
function changeContactRowType(input, newType, previousType) {
14681499
const inputCurrentValue = input.value.trim();
14691500

@@ -1512,18 +1543,63 @@
15121543
return true; // факт завершения
15131544
}
15141545

1515-
// ** обновление атрибута/значения "type" у/для row-инпута (кому возможно, после выбора)
1516-
function updateRowInputType(input, contactType) {
1517-
// объект для сопоставления (кому заменять, на какое значение)
1518-
const typeMapping = {
1519-
phone: 'tel',
1520-
'extra-phone': 'tel',
1521-
email: 'email',
1522-
};
1546+
// ** удаление строки row-контактов в модальном окне (через "X" кнопку, с/без уточняющего сообщения)
1547+
function deleteModalContactsElement(event) {
1548+
const clickedContactsXBtn = event.currentTarget; // получение ИМЕННО кнопки, а не/может внутренней иконки (согласно "размазанного" события)
15231549

1524-
// корректировка атрибута/значения "type" (или будет text)
1525-
const newType = typeMapping[contactType] || 'text';
1526-
input.setAttribute('type', newType);
1550+
if (clickedContactsXBtn) {
1551+
tippy.hideAll(); // предварительное скрытие всех/вдруг "активных" tooltips (перед удалением искомой строки)
1552+
1553+
// фиксация родительского элемента
1554+
const modalContactsElement = clickedContactsXBtn.closest(
1555+
'.modal__add-body-add-contact-element'
1556+
);
1557+
1558+
if (modalContactsElement) {
1559+
// удаление/исключение привязанного tooltip (к конкретной строке/кнопке)
1560+
if (clickedContactsXBtn._tippy) {
1561+
clickedContactsXBtn._tippy.destroy();
1562+
}
1563+
1564+
// определение заполненности инпута в данной строке контакта
1565+
const currentInput = modalContactsElement.querySelector(
1566+
'.modal__add-body-add-contact-input'
1567+
);
1568+
const isCurrentInputFilled =
1569+
currentInput && currentInput.value.trim() !== '';
1570+
let confirmed = true; // изначально подтверждение/confirm не требуется
1571+
1572+
if (isCurrentInputFilled) {
1573+
confirmed = confirm('Вы действительно хотите удалить этот контакт?'); // если/есть данные в инпуте, то тогда confirm/подтверждение при удалении
1574+
}
1575+
1576+
if (confirmed) {
1577+
modalContactsElement.remove(); // удаление строки контактов
1578+
1579+
// удаление строки контактов и из массива
1580+
const contactIndex =
1581+
addModalContactsArr.indexOf(modalContactsElement);
1582+
if (contactIndex > -1) addModalContactsArr.splice(contactIndex, 1);
1583+
1584+
// проверка на количество элементов в массиве, меньше 10.. возврат возможности прожатия кнопки "Добавить контакт"
1585+
if (addModalContactsArr.length < 10) {
1586+
addModalBodyAddBtn.disabled = false;
1587+
}
1588+
1589+
// проверка на количество строк контактов (нет, скрытие обвёртки/родителя и удаление дополнительных отступов)
1590+
if (
1591+
document.querySelectorAll('.modal__add-body-add-contact-element')
1592+
.length === 0
1593+
) {
1594+
const addBodySelectWrap = document.querySelector(
1595+
'.modal__add-body-add-contacts-row-wrap'
1596+
);
1597+
addBodySelectWrap.classList.add('d-none');
1598+
addModalBodyAddBtn.classList.remove('modal-btn-margin');
1599+
}
1600+
}
1601+
}
1602+
}
15271603
}
15281604

15291605
// ** организация проверки на "пустые" row-контакты, перед закрытием модального окна (вывод сообщения)
@@ -1589,65 +1665,6 @@
15891665

15901666
addModalWrap.addEventListener('hidden.bs.modal', removeInvalidRowContacts); // удаление/очистка от невалидных row-контактов (при закрытие add-модального окна)
15911667

1592-
// ** удаление строки контактов в add-модальном окне (через "X" кнопку, с/без уточняющего сообщения)
1593-
function deleteModalContactsElement(event) {
1594-
const clickedContactsXBtn = event.currentTarget; // получение ИМЕННО кнопки, а не/может внутренней иконки (согласно "размазанного" события)
1595-
1596-
if (clickedContactsXBtn) {
1597-
tippy.hideAll(); // предварительное скрытие всех/вдруг "активных" tooltips (перед удалением искомой строки)
1598-
1599-
// фиксация родительского элемента
1600-
const modalContactsElement = clickedContactsXBtn.closest(
1601-
'.modal__add-body-add-contact-element'
1602-
);
1603-
1604-
if (modalContactsElement) {
1605-
// удаление/исключение привязанного tooltip (к конкретной строке/кнопке)
1606-
if (clickedContactsXBtn._tippy) {
1607-
clickedContactsXBtn._tippy.destroy();
1608-
}
1609-
1610-
// определение заполненности инпута в данной строке контакта
1611-
const currentInput = modalContactsElement.querySelector(
1612-
'.modal__add-body-add-contact-input'
1613-
);
1614-
const isCurrentInputFilled =
1615-
currentInput && currentInput.value.trim() !== '';
1616-
let confirmed = true; // изначально подтверждение/confirm не требуется
1617-
1618-
if (isCurrentInputFilled) {
1619-
confirmed = confirm('Вы действительно хотите удалить этот контакт?'); // если/есть данные в инпуте, то тогда confirm/подтверждение при удалении
1620-
}
1621-
1622-
if (confirmed) {
1623-
modalContactsElement.remove(); // удаление строки контактов
1624-
1625-
// удаление строки контактов и из массива
1626-
const contactIndex =
1627-
addModalContactsArr.indexOf(modalContactsElement);
1628-
if (contactIndex > -1) addModalContactsArr.splice(contactIndex, 1);
1629-
1630-
// проверка на количество элементов в массиве, меньше 10.. возврат возможности прожатия кнопки "Добавить контакт"
1631-
if (addModalContactsArr.length < 10) {
1632-
addModalBodyAddBtn.disabled = false;
1633-
}
1634-
1635-
// проверка на количество строк контактов (нет, скрытие обвёртки/родителя и удаление дополнительных отступов)
1636-
if (
1637-
document.querySelectorAll('.modal__add-body-add-contact-element')
1638-
.length === 0
1639-
) {
1640-
const addBodySelectWrap = document.querySelector(
1641-
'.modal__add-body-add-contacts-row-wrap'
1642-
);
1643-
addBodySelectWrap.classList.add('d-none');
1644-
addModalBodyAddBtn.classList.remove('modal-btn-margin');
1645-
}
1646-
}
1647-
}
1648-
}
1649-
}
1650-
16511668
// ** дополнительная/местная организация логики для tooltips (т.е. помимо customTippy.js)
16521669
function initTippy(selector, content, side) {
16531670
// определение входящего элемента (селектор или DOM-элемент, поиск/корректировка)

0 commit comments

Comments
 (0)