todoapp-mvc

mvc pattern is used.

by shahryar saljoughi

HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link href="styles.css" type="text/css" rel="stylesheet">
  <link rel="stylesheet" href="js/myIconFramework/styles.css">
  <title>Document</title>
</head>
<body>
  <p class="title">Todo App</p>
  <div class="container">
    <div id="rightPanel" >
      
    </div>
    <div id="leftPanel">
      <input type="text" class="stack-item" id="descriptionInput">
      <button class="stack-item button createButton" onclick="addTodo()">New todo</button>
      <hr />  
      <button class="stack-item button yellowButton" onclick="makeVisibleElementsWithClass() & hideElementsWithClass('not-completed')">Completed</button>  
      <button class="stack-item button yellowButton" onclick="makeVisibleElementsWithClass() & hideElementsWithClass('completed')">Active</button>  
      <button class="stack-item button yellowButton" onclick="makeVisibleElementsWithClass()">All</button>  
    </div>
  </div>
  <!-- order of loading scripts matter!-->
  <script src="js/myIconFramework/scripts.js"></script>
  <script src="js/model.js"></script>
  <script src="js/view.js"></script>
  <script src="js/controller.js"></script>
</body>
</html>

CSS

* {
  box-sizing: border-box;
  font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
}
body {
  padding: 10%;
}
.container {
  display: flex;
  margin: auto;
  width: 80%;
  flex-direction: row;
}

div#leftPanel {
  flex: 1;
  display: flex;
  flex-direction: column;
  flex-shrink: 1;
}

div#rightPanel {
  flex: 3;
  flex-shrink: 1;
}

input {
  padding: 5px;
}

.stack-item {
  margin: 7px 0px 7px 0px;
  display: block;
}

.createButton {
  background-color: rgba(42, 129, 89, 0.486);
  color: white;
}

.button {
  padding: 10px;
  font-weight: bold;
  border-radius: 10px;
  cursor: pointer;
}

.yellowButton {
  background-color: rgba(160, 160, 52, 0.507);
  color: white;
}

.yellowButton:hover {
  background-color: rgb(104, 104, 7);
}

.createButton:hover {
  background-color: rgb(74, 119, 7);
}

.todo {
  padding: 10px;
  width: 80%;
  position: relative; /*this is because it has a child who wants to be absolutely positioned!. */
  margin: 10px auto 10px auto;
}
.todo:first-child {
  margin: auto;
}
.completed {
  border: rgb(4, 129, 71) solid;
  border-radius: 10px;
  background-color: rgba(4, 129, 71, 0.43);
}
.not-completed {
  border: #0000ff6b solid;
  border-radius: 10px;
  background-color: rgba(6, 110, 230, 0.47);
}

.close {
  color: red;
  font-weight: bold;
  position: absolute;
  top: 0px;
  right: 0px;
  cursor: pointer;
}
.title {
  text-align: center;
  display: block;
  
  font-size: 50px;
}

.actionsButtonContainer {
  width: 30px;
  height: 30px; 
  position: absolute;
  right: 5px;
  margin:  auto;
  top:  0px;
  z-index: 1;
}
.svg {
  width: 100%;
  height: 100%;
  padding: 0;
}

span[class*="icon"] {
  cursor: pointer;
}

.edit-icon {
  float: right;
}

.todo-edit-mode {
  background-color: rgba(209, 218, 221, 0.329);
  border: solid blue 1px;
}

.position-right {
  float: right;
}

.hidden {
  display: none;
}
@media screen and (max-width: 992px) {
  .container {
    flex-direction: column;
...

JavaScript

/* models.js */

function createModelsModule() {
  let items = [];
  
  /**
   * @param  {string} todoDescription
   */
  function addItem(todoDescription) {
    if (!todoDescription) {
      return;
    }
    items.push([description, items.length]);
    return items.length -1 ; 
  }
  
  function removeItem(todoIndex) {
    items.splice(todoIndex, todoIndex) ;
  }
  function getLastItem() {
    return items[items.length - 1];
  }
  return {
    removeItem: removeItem,
    addItem: addItem,
    getLastItem: getLastItem,
    getAll: () => items,
  }
  
}



/* views.js */




function createViewsModule() {
  var iconsModule = createIconModule();
  let panel = document.getElementById("rightPanel");

  /**
   * @param  {{todoDescription: string, todoIndex: number}} todo
   */
  function showTodo(todo) {
  
    var newTodo = document.createElement("div");
    var textNode = document.createElement("span");
    var removeButton = document.createElement("span");
    var editButton = document.createElement("span"); 
    var completionCheckbox = document.createElement("input");
    
    newTodo.classList.add("todo", "not-completed", "parent-of-hidden");
    removeButton.classList.add("remove-icon", "position-right", "visible-if-parent-hovered");
    textNode.classList.add("todo-text");
    editButton.classList.add("edit-icon", "visible-if-parent-hovered");
    
    textNode.innerText = todo[0]; 
    completionCheckbox.type = "checkbox";
    
    panel.appendChild(newTodo);
    newTodo.appendChild(textNode);
    newTodo.appendChild(removeButton);
    newTodo.appendChild(editButton);
    
    newTodo.insertBefore(completionCheckbox, newTodo.firstChild);

    iconsModule.triggerRendering();
  
    return {
      completionCheckBox: completionCheckbox,
      removeButton: removeButton,
      editButton: editButton,
      textNode: textNode,
      todoNode: newTodo,
      applyCompletedTodoStyle: () => applyCompletedTodoStyle(newTodo),
      applyNotCompletedTodoStyle: () =>...