0
\$\begingroup\$

Hello I've created to do app with some additional functionality.

Since I am new in JS I would love some feedback if you guys could point out some obvious mistakes/good practices/better solutions or implementations I will be grateful.

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style/main.css" />
    <title>To do app</title>
  </head>
  <body>
    <div class="container">
      <div class="banner">
        <h2>Welcome</h2>
        <div class="timestamp">
          <div class="timestamp__time">12:20</div>
          <div class="timestamp__date">Tuesday, 5 January</div>
        </div>
      </div>
      <div class="sidebar">
        <h3>Your lists</h3>
        <div class="lists">
          <div class="list active">
            <svg class="list__icon">
              <use xlink:href="img/icons/sprite.svg#icon-bookmark"></use>
            </svg>
            <input class="list__title" value="Important" readonly />
            <div class="list__options">
              <div class="option"></div>
              <div class="option"></div>
            </div>
          </div>
          <div class="list">
            <svg class="list__icon">
              <use xlink:href="img/icons/sprite.svg#icon-light-bulb"></use>
            </svg>
            <input class="list__title" value="Ideas" readonly />
            <div class="list__options">
              <div class="option"></div>
              <div class="option"></div>
            </div>
          </div>
          <div class="list">
            <svg class="list__icon">
              <use xlink:href="img/icons/sprite.svg#icon-shopping-basket"></use>
            </svg>
            <input class="list__title" value="Groceries" readonly />
            <div class="list__options">
              <div class="option"></div>
              <div class="option"></div>
            </div>
          </div>
        </div>
        <div class="add-list-container">
          <div class="add-list">
            <img src="img/plus.svg" alt="plus sign" />
            <p>New list</p>
          </div>
        </div>
      </div>
      <main class="main-section">
        <div class="main">
          <div class="todo show" id="Important">
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check item__check--done">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title item__title--done" value="Walk the dog" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title" value="Finish essay" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
          </div>
          <div class="todo" id="Ideas">
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title" value="Weight loss tracker" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title" value="Meal planning" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
          </div>
          <div class="todo" id="Groceries">
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title" value="Milk" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
            <div class="item">
              <div class="item__wrapper">
                <div class="item__check">
                  <img src="img/checkmark.svg" alt="checkmark" />
                </div>
                <input class="item__title" value="Broccoli" readonly />
              </div>
              <div class="item__options hide">
                <img src="img/pen.svg" alt="pen" class="item-rename" />
                <img src="img/trash.svg" alt="trash" class="item-delete" />
              </div>
            </div>
          </div>
        </div>
        <div class="add-item">
          <img src="img/plus.svg" alt="plus sign" />
          <p>New item</p>
        </div>
      </main>
    </div>

    <script src="script.js"></script>
  </body>
</html>

CSS (generated by SAS)

@import url("https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600&display=swap");
*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  text-decoration: none;
  -webkit-box-sizing: border-box;
          box-sizing: border-box;
  font-family: 'Quicksand', sans-serif;
}

html {
  font-size: 62.5%;
}

body {
  height: 100vh;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}

.container {
  display: -ms-grid;
  display: grid;
  width: 100%;
  height: 100%;
      grid-template-areas: 'banner banner banner'
 'sidebar main main'
 'sidebar main main';
  -ms-grid-columns: 35rem 1fr 1fr;
      grid-template-columns: 35rem 1fr 1fr;
  -ms-grid-rows: 23rem 1fr 1fr;
      grid-template-rows: 23rem 1fr 1fr;
}

.container .main-section {
  -ms-grid-row: 2;
  -ms-grid-row-span: 2;
  -ms-grid-column: 2;
  -ms-grid-column-span: 2;
  grid-area: main;
}

.banner {
  background-image: url(../img/banner.svg);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: bottom;
  -ms-grid-row: 1;
  -ms-grid-column: 1;
  -ms-grid-column-span: 3;
  grid-area: banner;
  color: #fff;
  padding: 3rem 5rem;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
}

.banner .timestamp__time {
  font-size: 7rem;
  font-weight: 300;
}

.banner .timestamp__date {
  font-weight: 500;
  font-size: 2rem;
}

.banner h2 {
  font-size: 3rem;
  font-weight: 600;
}

.sidebar {
  background-color: #f5f5f5;
  -ms-grid-row: 2;
  -ms-grid-row-span: 2;
  -ms-grid-column: 1;
  grid-area: sidebar;
}

.sidebar h3 {
  margin-bottom: 4rem;
  margin-top: 5rem;
  font-size: 2.5rem;
  font-weight: 600;
  padding: 0 5rem;
}

.sidebar .list {
  display: -ms-grid;
  display: grid;
  -ms-grid-columns: (1fr)[3];
      grid-template-columns: repeat(3, 1fr);
  padding: 2rem 5rem;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  position: relative;
}

.sidebar .list__icon {
  width: 2.2rem;
  height: 2.2rem;
  fill: currentColor;
}

.sidebar .list:hover {
  background-color: #fff;
  cursor: pointer;
}

.sidebar .list__title {
  font-size: 2rem;
  margin-left: 0.5rem;
  background: none;
  border: none;
  color: #000;
  outline: none;
  display: inline-block;
  cursor: pointer;
}

.sidebar .list .icon-modal {
  border-radius: 3px;
  padding: 3rem;
  margin-left: 5rem;
  position: absolute;
  background-color: #fff;
  bottom: 100%;
  width: 100%;
}

.sidebar .list .icon-modal > * {
  margin: 0.7rem;
  fill: black;
  cursor: pointer;
}

.sidebar .list .icon-modal::after {
  position: absolute;
  content: '';
  left: 0;
  top: 100%;
  width: 0;
  height: 0;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  border-top: 15px solid #fff;
}

.sidebar .list__options {
  position: relative;
  padding: 0.5rem;
}

.sidebar .list__options .list-modal {
  position: absolute;
  background-color: white;
  color: black;
  bottom: 100%;
  left: 50%;
  -webkit-transform: translateX(-50%);
          transform: translateX(-50%);
  width: 10rem;
  font-weight: 600;
  font-size: 1.2rem;
  margin-bottom: 1rem;
}

.sidebar .list__options .list-modal p {
  padding: 0.5rem 1rem;
}

.sidebar .list__options .list-modal p:hover {
  cursor: pointer;
  background-color: #ff3366;
  color: #fff;
}

.sidebar .list .icon-modal-close {
  width: 2rem;
  height: 2rem;
  position: absolute;
  top: 5px;
  right: 5px;
}

.sidebar .list .option {
  background-color: black;
  width: 0.6rem;
  border-radius: 50%;
  height: 0.6rem;
}

.sidebar .list .option:first-child {
  margin-bottom: 0.6rem;
}

.sidebar .add-list-container {
  padding: 2rem 5rem;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  font-size: 2rem;
}

.sidebar .add-list-container .add-list {
  cursor: pointer;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -ms-flex-item-align: start;
      align-self: flex-start;
}

.sidebar .add-list-container .add-list img {
  width: 3rem;
}

.todo {
  font-size: 5rem;
  display: none;
}

.item {
  padding: 3rem 5rem;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-shadow: 0 2px 2px -2px gray;
          box-shadow: 0 2px 2px -2px gray;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
}

.item__wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}

.item__check {
  width: 2.5rem;
  height: 2.5rem;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  border-radius: 50%;
  border: 1px solid black;
  cursor: pointer;
}

.item__check--done {
  background-color: #40d628;
  border: none;
}

.item__check img {
  width: 1.5rem;
  height: 1.5rem;
}

.item__title {
  font-size: 2rem;
  margin-left: 1rem;
  background: none;
  border: none;
  color: #000;
  outline: none;
  display: inline-block;
}

.item__title--done {
  text-decoration: line-through;
}

.item__options {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

.item__options img {
  cursor: pointer;
  width: 2.5rem;
  height: 2.5rem;
}

.item__options img:not(:first-child) {
  margin-left: 2rem;
}

.add-item {
  padding: 3rem 5rem;
  -webkit-box-shadow: 0 2px 2px -2px gray;
          box-shadow: 0 2px 2px -2px gray;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  font-size: 2rem;
  cursor: pointer;
}

.add-item img {
  width: 3rem;
}

.active {
  background-color: #ff3366;
  color: #fff;
}

.active .list__title {
  color: white !important;
  cursor: auto;
}

.active .list__icon {
  fill: currentColor;
}

.active:hover {
  background-color: #ff3366 !important;
  cursor: auto !important;
}

.active .option {
  background-color: white !important;
}

.show {
  display: block;
}

.hide {
  display: none !important;
}
/*# sourceMappingURL=main.css.map */

JS

'use strict';

// #######################################
// DATE & TIME

const timeBox = document.querySelector('.timestamp__time');
const dateBox = document.querySelector('.timestamp__date');

let now, hours, minutes;
const clock = () => {
  now = new Date();
  hours = now.getHours();
  minutes = now.getMinutes();

  hours < 10 ? (hours = `0${hours}`) : hours;
  minutes < 10 ? (minutes = `0${minutes}`) : minutes;

  timeBox.textContent = `${hours}:${minutes}`;
};
setInterval(clock, 1000);

const setDate = () => {
  now = new Date();
  let weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  let months = ['January', 'February', 'March', 'April', 'May', 'Juny', 'July', 'August', 'September', 'October', 'November', 'December'];

  // now.getDay() - returns 0-6
  let weekDay = weekDays[now.getDay()];
  let day = now.getDate();
  let month = months[now.getMonth()];

  dateBox.textContent = `${weekDay}, ${day} ${month}`;
};

setDate();

// #######################################
// SWITCHING BETWEEN LISTS
const listsContainer = document.querySelector('.lists');
let lists = document.querySelectorAll('.list');
let activeList = lists[0];

// Add eventListener to lists
const setUpListsListeners = () => {
  lists = document.querySelectorAll('.list');

  for (let i = 0; i < lists.length; i++) {
    lists[i].addEventListener('click', () => {
      if (!lists[i]) return;
      if (!lists[i].classList.contains('active')) switchList(lists[i]); // listener only for non active lists
    });
  }
};
// call to setUp 3 primary lists
setUpListsListeners();

const switchList = (list) => {
  if (typeof activeList !== 'undefined') {
    // for more than 1 list
    // 'turn off' active list
    activeList.classList.toggle('active');
    document.querySelector(`#${activeList.children[1].value}`).classList.toggle('show');
  }
  // switch list by 'turning on' list from param
  activeList = list;
  activeList.classList.toggle('active');
  document.querySelector(`#${activeList.children[1].value}`).classList.toggle('show'); // display to'do items for this list
};

// #######################################
// MODAL

// parent in this case is a list in which we click settings - prevents opening multiple modals
let optionsParent;

const openModal = (parent) => {
  // create 3 different elements for each event - icon change, rename, delete
  const modal = document.createElement('div');
  modal.className = 'list-modal';

  const rename = document.createElement('p');
  rename.className = 'rename';
  rename.textContent = 'Rename';
  modal.appendChild(rename);

  const changeIcon = document.createElement('p');
  changeIcon.className = 'change-icon';
  changeIcon.textContent = 'Change icon';
  modal.appendChild(changeIcon);

  const deleteList = document.createElement('p');
  deleteList.className = 'delete';
  deleteList.textContent = 'Delete';
  modal.appendChild(deleteList);

  parent.appendChild(modal);
  optionsParent = parent;
  activateModalButtons();
};

const closeModal = (parent) => {
  const modal = document.querySelector('.list-modal');
  if (!modal) return;
  parent.removeChild(modal);
  optionsParent = false;
};

// function that checks if we click in either option circular icon or it's container
// if it's already opened and we click outside it - closeModal()
// if yes then openModal()
window.addEventListener('click', function (e) {
  if (optionsParent) closeModal(optionsParent);
  if (e.target.classList.contains('list__options')) openModal(e.target);
  if (e.target.classList.contains('option')) openModal(e.target);
});

// #######################################
// MODAL - RENAME, CHANGE ICON & DELETE

const activateModalButtons = () => {
  const renameBtn = document.querySelector('.rename');
  const deleteBtn = document.querySelector('.delete');
  const changeIconBtn = document.querySelector('.change-icon');

  const currentList = activeList.children[1];

  renameBtn.addEventListener('click', () => {
    renameList(currentList);
  });

  deleteBtn.addEventListener('click', (e) => {
    e.stopPropagation();

    // remove lists on which we click delete button
    listsContainer.removeChild(activeList);
    document.querySelector(`#${activeList.children[1].value}`).classList.add('hide');
    lists = document.querySelectorAll('.list');

    // activate first list
    activeList = lists[0];
    if (!activeList) return; // return when there is no more lists
    activeList.classList.toggle('active');
    document.querySelector(`#${activeList.children[1].value}`).classList.toggle('show');

    // refresh listeners for lists
    setUpListsListeners();
  });

  changeIconBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    openIconModal(activeList);
  });
};

// icon change
const openIconModal = (parent) => {
  const iconModal = document.createElement('div');
  iconModal.className = 'icon-modal';

  iconModal.innerHTML = `
  <svg class="list__icon" id="icon-shopping-basket">
    <use xlink:href="img/icons/sprite.svg#icon-shopping-basket"></use>
  </svg>

  <svg class="list__icon" id="icon-bookmark">
    <use xlink:href="img/icons/sprite.svg#icon-bookmark"></use>
  </svg> 

  <svg class="list__icon" id="icon-beamed-note">
    <use xlink:href="img/icons/sprite.svg#icon-beamed-note"></use>
  </svg>

  <svg class="list__icon" id="icon-bowl">
    <use xlink:href="img/icons/sprite.svg#icon-bowl"></use>
  </svg>

  <svg class="list__icon" id="icon-clipboard">
    <use xlink:href="img/icons/sprite.svg#icon-clipboard"></use>
  </svg>

  <svg class="list__icon" id="icon-credit-card">
    <use xlink:href="img/icons/sprite.svg#icon-credit-card"></use>
  </svg>

  <svg class="list__icon" id="icon-globe">
    <use xlink:href="img/icons/sprite.svg#icon-globe"></use>
  </svg>

  <svg class="list__icon" id="icon-heart">
    <use xlink:href="img/icons/sprite.svg#icon-heart"></use>
  </svg>

  <svg class="list__icon" id="icon-home">
    <use xlink:href="img/icons/sprite.svg#icon-home"></use>
  </svg>

  <svg class="list__icon" id="icon-hour-glass">
    <use xlink:href="img/icons/sprite.svg#icon-hour-glass"></use>
  </svg>

  <svg class="list__icon" id="icon-laptop">
    <use xlink:href="img/icons/sprite.svg#icon-laptop"></use>
  </svg>

  <svg class="list__icon" id="icon-light-bulb">
    <use xlink:href="img/icons/sprite.svg#icon-light-bulb"></use>
  </svg>

  <svg class="list__icon" id="icon-location-pin">
    <use xlink:href="img/icons/sprite.svg#icon-location-pin"></use>
  </svg>

  <svg class="list__icon" id="icon-thumbs-up">
    <use xlink:href="img/icons/sprite.svg#icon-thumbs-up"></use>
  </svg>

  <svg class="list__icon" id="icon-suitcase">
    <use xlink:href="img/icons/sprite.svg#icon-suitcase"></use>
  </svg>

  <svg class="list__icon" id="icon-mail">
    <use xlink:href="img/icons/sprite.svg#icon-mail"></use>
  </svg>

  <img src="img/close.svg" class="icon-modal-close">
  `;

  parent.appendChild(iconModal);

  const iconModalCloseBtn = document.querySelector('.icon-modal-close');
  let isModal = true;
  iconModalCloseBtn.addEventListener('click', (e) => {
    e.stopPropagation();
    isModal = false;
    parent.removeChild(iconModal);
  });

  window.addEventListener('click', () => {
    if (isModal) {
      parent.removeChild(iconModal);
      isModal = false;
    }
  });

  const listIcons = document.querySelectorAll('.list__icon');
  for (const icon of listIcons) {
    icon.addEventListener('click', () => {
      activeList.children[0].children[0].setAttributeNS('http://www.w3.org/1999/xlink', 'href', `img/icons/sprite.svg#${icon.id}`);
    });
  }
};

const renameList = (currentList) => {
  // place cursor in list name (focus input)
  currentList.readOnly = false;
  setCaretPosition(currentList, currentList.value.length);

  // rename it on either enter key or blur
  const tmpName = currentList.value;
  currentList.addEventListener('blur', () => {
    if (!document.querySelector(`#${tmpName}`)) return; // prevent executing both events
    currentList.readOnly = true;
    document.querySelector(`#${tmpName}`).id = currentList.value;
  });

  currentList.addEventListener('keyup', () => {
    if (event.keyCode === 13) {
      if (!document.querySelector(`#${tmpName}`)) return;
      currentList.readOnly = true;
      document.querySelector(`#${tmpName}`).id = currentList.value;
    }
  });
};

// #######################################
// ADD NEW LIST

const addListBtn = document.querySelector('.add-list');
const main = document.querySelector('.main');
let newListsNumber = 1;
addListBtn.addEventListener('click', () => {
  // create new list
  const newList = document.createElement('div');
  newList.className = 'list';

  newList.innerHTML = `
  <svg class="list__icon">
    <use xlink:href="img/icons/sprite.svg#icon-clipboard"></use>
  </svg>  
  <input class="list__title" value="New-${newListsNumber}" readonly />
  <div class="list__options">
    <div class="option"></div>
    <div class="option"></div>
  </div>`;

  listsContainer.appendChild(newList);

  // create new item for current list
  const newTodo = document.createElement('div');
  newTodo.className = 'todo';
  newTodo.id = newList.children[1].value;

  main.appendChild(newTodo);

  setUpListsListeners();
  renameList(newList.children[1]);
  newListsNumber++;
});

// #######################################
// ITEMS - DISPLAY TRASH AND RENAME ICON ON HOVER
let currentItem;

const setUpItems = () => {
  const items = document.querySelectorAll('.item');

  for (const item of items) {
    item.addEventListener('mouseover', () => {
      item.children[1].classList.remove('hide');
      currentItem = item;
    });
    item.addEventListener('mouseout', () => {
      item.children[1].classList.add('hide');
    });
  }

  // RENAME BUTTONS
  const renameItemButtons = document.querySelectorAll('.item-rename');
  for (const renameBtn of renameItemButtons) {
    renameBtn.addEventListener('click', () => {
      const itemName = currentItem.children[0].children[1];
      if (itemName.classList.contains('item__title--done')) return;
      renameItem(itemName);
    });
  }

  // DELETE BUTTONS
  const deleteItemButtons = document.querySelectorAll('.item-delete');
  for (const deleteBtn of deleteItemButtons) {
    deleteBtn.addEventListener('click', () => {
      currentItem.remove();
    });
  }
};

// #######################################
// MARK AS DONE

// for default items
const checkBoxes = document.querySelectorAll('.item__check');

for (const checkBox of checkBoxes) {
  checkBox.addEventListener('click', () => {
    checkBox.classList.toggle('item__check--done');
    currentItem.children[0].children[1].classList.toggle('item__title--done');
  });
}

// for new items
const markAsDoneAddListener = () => {
  currentItem.children[0].children[0].classList.toggle('item__check--done');
  currentItem.children[0].children[1].classList.toggle('item__title--done');
};

setUpItems();

// #######################################
// ADD ITEM
const addItemBtn = document.querySelector('.add-item');

addItemBtn.addEventListener('click', () => {
  const itemParent = document.querySelector(`#${activeList.children[1].value}`);

  const newItem = document.createElement('div');
  newItem.className = 'item';

  newItem.innerHTML = `
  <div class="item__wrapper">
  <div class="item__check" onClick="markAsDoneAddListener()">
    <img src="img/checkmark.svg" alt="checkmark" />
  </div>
  <input class="item__title" value="New item" readonly />
  </div>
  <div class="item__options hide">
    <img src="img/pen.svg" alt="pen" class="item-rename"/>
    <img src="img/trash.svg" alt="trash" class="item-delete" />
  </div>`;

  itemParent.appendChild(newItem);

  setUpItems();
  renameItem(newItem.children[0].children[1]);
});

// #######################################
// RENAME ITEM
const renameItem = (itemName) => {
  // place cursor in list name (focus input)
  itemName.readOnly = false;
  setCaretPosition(itemName, itemName.value.length);

  // rename it on either enter key or blur
  const tmpName = itemName.value;
  itemName.addEventListener('blur', () => {
    if (!document.querySelector(`#${tmpName}`)) return; // prevent executing both events
    itemName.readOnly = true;
    document.querySelector(`#${tmpName}`).id = itemName.value;
  });

  itemName.addEventListener('keyup', () => {
    if (event.keyCode === 13) {
      if (!document.querySelector(`#${tmpName}`)) return;
      itemName.readOnly = true;
      document.querySelector(`#${tmpName}`).id = itemName.value;
    }
  });
};

// #######################################
// SET CURSOR INSIDE INPUT
function setCaretPosition(ctrl, pos) {
  // Modern browsers
  if (ctrl.setSelectionRange) {
    ctrl.focus();
    ctrl.setSelectionRange(pos, pos);

    // IE8 and below
  } else if (ctrl.createTextRange) {
    var range = ctrl.createTextRange();
    range.collapse(true);
    range.moveEnd('character', pos);
    range.moveStart('character', pos);
    range.select();
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ Hello. I made a pretty long answer that might be helpful for You. Take a look :) \$\endgroup\$ – AdamKniec Jan 15 at 22:06
1
\$\begingroup\$

HTML:

  • Your input elements do not have associated labels
  • Use semantic html elements. Why do You use img instead of a regular html button ?

CSS:

  • Avoid styling by tags. Use classes instead
  • Avoid using !important. Read about CSS specificity
  • I'd personally create a separate CSS file with the colors
  • I'm pretty sure You do not need all of those prefixes

JS:

  • Some of Your let's might be changed to const's
  • // Add eventListener to lists. Code below this comment could be improved. You are adding an event listener to all of the list items. Read about event delegation. It will allow You to add the listener to one item only when it's clicked :)
  • I would try to handle adding the list items in a different way. Maybe using insterAdjacentHTML and template strings. Read about that
  • if (e.target.classList.contains('list__options')) openModal(e.target); Use curly braces in if/else statements
  • renameBtn.addEventListener('click', () => { renameList(currentList); }); This could be an one liner
  • if (!activeList) return; // return when there is no more lists This code is self explanatory. There is no need to add such a comment
  • There is no need to add () around one argument in arrow syntax
  • Sometimes You use regular function and sometimes arrow function.
  • Avoid using var. We have better alternatives nowadays
  • Adding and removing the list items could be improved using ES6 methods. I'd add new items onClick by pushing data to some kind of an items array. Based on that array I'd use .map method to loop over that array and render proper items on the page. Removing could be handled using event delegation and .filter method
\$\endgroup\$
1
  • \$\begingroup\$ thanks for the feedback and your time \$\endgroup\$ – fluffy Jan 16 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.