├── db └── db.json ├── index.html └── src ├── css └── style.css └── js └── index.js /db/db.json: -------------------------------------------------------------------------------- 1 | { 2 | "todos": [ 3 | { 4 | "title": "sd", 5 | "completed": false, 6 | "id": 1 7 | }, 8 | { 9 | "completed": true, 10 | "id": 2, 11 | "title": "ff" 12 | }, 13 | { 14 | "completed": true, 15 | "id": 3, 16 | "title": "ff" 17 | }, 18 | { 19 | "completed": true, 20 | "id": 4, 21 | "title": "ggg" 22 | }, 23 | { 24 | "title": "s", 25 | "completed": false, 26 | "id": 5 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | HW23-js-jquery-part2 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

Tasks

17 |
18 |
19 |
    20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/css/style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | height: 100vh; 9 | font: 22px 'Helvetica Neue', Helvetica, Arial, sans-serif; 10 | line-height: 1.2em; 11 | background: linear-gradient(to right, #4e65d4 0%, #293dcb 19%, #4246a5 60%, #505ac2 100%); 12 | display: flex; 13 | align-items: center; 14 | justify-content: center; 15 | color: #fff; 16 | } 17 | 18 | ul { 19 | list-style-type: none; 20 | -webkit-padding-start: 0; 21 | } 22 | 23 | .btn { 24 | cursor: pointer; 25 | font-size: 15px; 26 | padding: 10px 20px; 27 | border-radius: 2em; 28 | background: none; 29 | border: 1px solid #fff; 30 | transition: 250ms ease-out; 31 | } 32 | 33 | .btn-danger:hover { 34 | color: #fff; 35 | background: #e74c3c; 36 | } 37 | 38 | .btn-success:hover { 39 | color: #fff; 40 | background: #05b437; 41 | } 42 | 43 | .btn:focus { 44 | color: #fff; 45 | outline: none; 46 | } 47 | 48 | .container { 49 | width: 400px; 50 | min-height: 500px; 51 | box-shadow: 0 20px 80px rgba(0,0,0,0.6); 52 | position: relative; 53 | border-radius: 1em; 54 | padding: 15px; 55 | display: flex; 56 | flex-direction: column; 57 | justify-content: space-between; 58 | } 59 | 60 | .header { 61 | display: flex; 62 | justify-content: space-around; 63 | } 64 | .header h2 { 65 | margin: 0; 66 | } 67 | 68 | .task-count { 69 | align-self: center; 70 | } 71 | 72 | .todo-list:first-of-type { 73 | border-top: 1px solid #f5f4f4; 74 | } 75 | 76 | .list-item-view { 77 | padding-top: 12px; 78 | padding-bottom: 12px; 79 | display: flex; 80 | align-items: center; 81 | justify-content: space-between; 82 | } 83 | 84 | .form { 85 | margin-bottom: 10px; 86 | display: flex; 87 | justify-content: center; 88 | } 89 | 90 | .input-text { 91 | height: 40px; 92 | font-size: 15px; 93 | border: 1px solid #dce4ec; 94 | width: 100%; 95 | margin-right: 15px; 96 | border-radius: 2em; 97 | padding: 5px 10px; 98 | transition: border 250ms ease-out; 99 | } 100 | 101 | .input-text:focus { 102 | border: 1px solid; 103 | outline: none; 104 | } 105 | 106 | 107 | .completed { 108 | text-decoration: line-through; 109 | } 110 | 111 | input[type="checkbox"] { 112 | display: none; 113 | } 114 | 115 | .list-item-view label:hover { 116 | cursor: pointer; 117 | } 118 | .list-item-view label { 119 | color: #e6ff01; 120 | } 121 | .list-item-view label.completed { 122 | color: #00f204; 123 | } 124 | 125 | #todos { 126 | max-height: 500px; 127 | overflow: auto; 128 | } 129 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | const resource = 'http://localhost:3000' 2 | const $todosSection = $('#todos') 3 | const $formAddTask = $('#addTask') 4 | let todos = [] 5 | 6 | async function deleteTask(id) { 7 | return await $.ajax({ 8 | url: `${resource}/todos/${id}`, 9 | method: 'DELETE' 10 | }) 11 | } 12 | 13 | async function addTask(data) { 14 | return await $.ajax({ 15 | url: `${resource}/todos`, 16 | method: 'POST', 17 | headers: { 18 | 'Content-Type': 'application/json' 19 | }, 20 | data: JSON.stringify(data) 21 | }) 22 | } 23 | 24 | async function changeTask(data) { 25 | return await $.ajax({ 26 | url: `${resource}/todos/${data.id}`, 27 | method: 'PUT', 28 | headers: { 29 | 'Content-Type': 'application/json' 30 | }, 31 | data: JSON.stringify(data) 32 | }) 33 | } 34 | 35 | function draw(whereDraw) { 36 | let todosContainer = '' 37 | todos.forEach(todo => { 38 | todosContainer += templateTodo(todo) 39 | }) 40 | whereDraw.html(todosContainer) 41 | } 42 | function templateTodo(data) { 43 | return `
  • 44 |
    45 | 48 | 49 |
    50 |
  • ` 51 | } 52 | 53 | $.ajax({ 54 | url: `${resource}/todos` 55 | }) 56 | .then((res) => { 57 | todos = res 58 | draw($todosSection) 59 | }) 60 | 61 | async function handlerDeleteTask(event) { 62 | const $parentEl = $(event.target).closest('.todo-list') 63 | const id = $parentEl.data('id') 64 | await deleteTask(id) 65 | $parentEl.remove() 66 | } 67 | 68 | async function handlerMarkedTask(event) { 69 | const $parentEl = $(event.target).closest('.todo-list') 70 | const id = $parentEl.data('id') 71 | const status = $parentEl.data('completed') 72 | const title = $parentEl.data('title') 73 | let newStatus = !Boolean(+status) 74 | 75 | await changeTask({ 76 | completed: newStatus, 77 | id, 78 | title 79 | }) 80 | $parentEl.data('completed', newStatus ? '1' : '0') 81 | const $label = $(event.target).closest('label') 82 | if (newStatus) { 83 | $label.addClass('completed') 84 | } else { 85 | $label.removeClass('completed') 86 | } 87 | } 88 | 89 | 90 | $formAddTask.submit((event) => handlerAddTask(event)) 91 | 92 | async function handlerAddTask(event) { 93 | const $input = $(event.target).children('input') 94 | event.preventDefault() 95 | const res = await addTask({ 96 | title: $input.val(), 97 | completed: false 98 | }) 99 | const el = templateTodo(res) 100 | $todosSection.append(el) 101 | $input.val('') 102 | } 103 | 104 | $todosSection.click((event) => { 105 | switch (event.target.tagName) { 106 | case 'LABEL': 107 | handlerMarkedTask(event) 108 | break; 109 | case 'BUTTON': 110 | handlerDeleteTask(event) 111 | break; 112 | } 113 | }) 114 | 115 | --------------------------------------------------------------------------------