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