1
This commit is contained in:
commit
5c9144b8cf
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
||||
Do uruchomienia może być potrzebny pakiet, npm install express body-parser xlsx
|
7
count_a.awk
Normal file
7
count_a.awk
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
count += gsub(/a/, "a");
|
||||
}
|
||||
END {
|
||||
print count;
|
||||
}
|
||||
|
BIN
data/todos.xlsx
Normal file
BIN
data/todos.xlsx
Normal file
Binary file not shown.
1340
package-lock.json
generated
Normal file
1340
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
package.json
Normal file
17
package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "todo",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^1.20.2",
|
||||
"express": "^4.19.2",
|
||||
"xlsx": "^0.18.5"
|
||||
}
|
||||
}
|
21
public/index.html
Normal file
21
public/index.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Todo List</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Todo List</h1>
|
||||
<form id="todo-form">
|
||||
<input type="text" id="todo-input" placeholder="Add a new task" required>
|
||||
<button type="submit">Add</button>
|
||||
</form>
|
||||
<ul id="todo-list"></ul>
|
||||
<button id="count-a-button">Count 'a' letters</button>
|
||||
<div id="count-a-result"></div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
78
public/script.js
Normal file
78
public/script.js
Normal file
@ -0,0 +1,78 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const todoForm = document.getElementById('todo-form');
|
||||
const todoInput = document.getElementById('todo-input');
|
||||
const todoList = document.getElementById('todo-list');
|
||||
const countAButton = document.getElementById('count-a-button');
|
||||
const countAResult = document.getElementById('count-a-result');
|
||||
|
||||
todoForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const task = todoInput.value;
|
||||
if (task) {
|
||||
addTodoToServer(task);
|
||||
todoInput.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
countAButton.addEventListener('click', () => {
|
||||
countA();
|
||||
});
|
||||
|
||||
function addTodoToServer(task) {
|
||||
fetch('/todos', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ task })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
appendTodoToList(data.data.id, data.data.task);
|
||||
});
|
||||
}
|
||||
|
||||
function appendTodoToList(id, task) {
|
||||
const todoItem = document.createElement('li');
|
||||
todoItem.textContent = task;
|
||||
todoItem.dataset.id = id;
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.textContent = 'Delete';
|
||||
deleteButton.addEventListener('click', () => {
|
||||
deleteTodoFromServer(id, todoItem);
|
||||
});
|
||||
todoItem.appendChild(deleteButton);
|
||||
todoList.appendChild(todoItem);
|
||||
}
|
||||
|
||||
function deleteTodoFromServer(id, todoItem) {
|
||||
fetch(`/todos/${id}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(() => {
|
||||
todoList.removeChild(todoItem);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchTodos() {
|
||||
fetch('/todos')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
data.data.forEach(todo => {
|
||||
appendTodoToList(todo.id, todo.task);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function countA() {
|
||||
fetch('/count-a')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
countAResult.textContent = `Number of 'a' letters: ${data.count}`;
|
||||
});
|
||||
}
|
||||
|
||||
fetchTodos();
|
||||
});
|
||||
|
76
public/styles.css
Normal file
76
public/styles.css
Normal file
@ -0,0 +1,76 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f0f4f7;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
#todo-list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#todo-list li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
margin-bottom: 10px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#todo-list li button {
|
||||
background-color: #dc3545;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#todo-list li button:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
#count-a-button {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#count-a-result {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
63
server.js
Normal file
63
server.js
Normal file
@ -0,0 +1,63 @@
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const xlsx = require('xlsx');
|
||||
const fs = require('fs');
|
||||
const { exec } = require('child_process');
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
const filePath = './data/todos.xlsx';
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(express.static('public'));
|
||||
|
||||
function readTodos() {
|
||||
if (fs.existsSync(filePath)) {
|
||||
const workbook = xlsx.readFile(filePath);
|
||||
const sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
return xlsx.utils.sheet_to_json(sheet);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function writeTodos(todos) {
|
||||
const worksheet = xlsx.utils.json_to_sheet(todos);
|
||||
const workbook = xlsx.utils.book_new();
|
||||
xlsx.utils.book_append_sheet(workbook, worksheet, 'Todos');
|
||||
xlsx.writeFile(workbook, filePath);
|
||||
}
|
||||
|
||||
app.get('/todos', (req, res) => {
|
||||
const todos = readTodos();
|
||||
res.json({ data: todos });
|
||||
});
|
||||
|
||||
app.post('/todos', (req, res) => {
|
||||
const todos = readTodos();
|
||||
const task = req.body.task;
|
||||
const newTodo = { id: todos.length ? todos[todos.length - 1].id + 1 : 1, task: task };
|
||||
todos.push(newTodo);
|
||||
writeTodos(todos);
|
||||
res.json({ data: newTodo });
|
||||
});
|
||||
|
||||
app.delete('/todos/:id', (req, res) => {
|
||||
const todos = readTodos();
|
||||
const updatedTodos = todos.filter(todo => todo.id != req.params.id);
|
||||
writeTodos(updatedTodos);
|
||||
res.json({ message: "success" });
|
||||
});
|
||||
|
||||
app.get('/count-a', (req, res) => {
|
||||
const todos = readTodos();
|
||||
const allTasks = todos.map(todo => todo.task).join('\n');
|
||||
fs.writeFileSync('tasks.txt', allTasks);
|
||||
exec('awk -f count_a.awk tasks.txt', (error, stdout) => {
|
||||
res.json({ count: parseInt(stdout.trim(), 10) });
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user