194 lines
7.2 KiB
JavaScript
194 lines
7.2 KiB
JavaScript
// --- Basic Todo Model ---
|
|
const STORAGE_KEY = 'todos-v1';
|
|
const CATEGORY_KEY = 'todo-categories';
|
|
let todos = [];
|
|
let categories = [];
|
|
|
|
function loadTodos() {
|
|
todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
|
|
categories = JSON.parse(localStorage.getItem(CATEGORY_KEY) || '[]');
|
|
}
|
|
|
|
function saveTodos() {
|
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
|
|
localStorage.setItem(CATEGORY_KEY, JSON.stringify(categories));
|
|
}
|
|
|
|
function getNextId() {
|
|
return todos.length ? Math.max(...todos.map(t => t.id)) + 1 : 1;
|
|
}
|
|
|
|
function renderForm() {
|
|
const form = document.getElementById('todo-form');
|
|
form.innerHTML = `
|
|
<div class="form-section">
|
|
<label for="task">Task Description</label>
|
|
<input type="text" id="task" placeholder="Task Description" required>
|
|
</div>
|
|
|
|
<div class="form-section grid-3">
|
|
<div>
|
|
<label for="creation-date">Creation Date</label>
|
|
<input type="date" id="creation-date" title="Creation Date">
|
|
</div>
|
|
<div>
|
|
<label for="next-date">Next Planned Work Date</label>
|
|
<input type="date" id="next-date" title="Next Planned Work Date">
|
|
</div>
|
|
<div>
|
|
<label for="due-date">Due Date</label>
|
|
<input type="date" id="due-date" title="Due Date">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-section grid-3">
|
|
<div>
|
|
<label for="status">Status</label>
|
|
<select id="status">
|
|
<option value="">(Blank)</option>
|
|
<option value="Busy">Busy</option>
|
|
<option value="Done">Done</option>
|
|
<option value="W4A">W4A</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="urgent">Urgent (1-7)</label>
|
|
<input type="number" id="urgent" min="1" max="7" placeholder="Urgent (1-7)">
|
|
</div>
|
|
<div>
|
|
<label for="importance">Importance (1-7)</label>
|
|
<input type="number" id="importance" min="1" max="7" placeholder="Importance (1-7)">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-section grid-2">
|
|
<div>
|
|
<label for="time-estimation">Time Estimation (min)</label>
|
|
<input type="number" id="time-estimation" min="0" placeholder="Time Est. (min)">
|
|
</div>
|
|
<div>
|
|
<label for="actual-time">Actual Time Spent (min)</label>
|
|
<input type="number" id="actual-time" min="0" placeholder="Actual Time (min)">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-section grid-2">
|
|
<div>
|
|
<label for="category">Category</label>
|
|
<input type="text" id="category" placeholder="Category" list="category-list">
|
|
<datalist id="category-list"></datalist>
|
|
</div>
|
|
<div>
|
|
<label for="linked-tasks">Link with other tasks (IDs, comma separated)</label>
|
|
<input type="text" id="linked-tasks" placeholder="Link with other tasks (IDs, comma separated)">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-section grid-2">
|
|
<div>
|
|
<label for="coms">Coms URL</label>
|
|
<input type="url" id="coms" placeholder="Coms URL">
|
|
</div>
|
|
<div>
|
|
<label for="link">Link URL</label>
|
|
<input type="url" id="link" placeholder="Link URL">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-section">
|
|
<label for="comments">Comments</label>
|
|
<textarea id="comments" placeholder="Comments"></textarea>
|
|
</div>
|
|
|
|
<button type="submit" class="add-todo-btn">Add Todo</button>
|
|
`;
|
|
// Autocomplete for categories
|
|
const datalist = document.getElementById('category-list');
|
|
datalist.innerHTML = categories.map(cat => `<option value="${cat}">`).join('');
|
|
}
|
|
|
|
function renderTodos() {
|
|
const list = document.getElementById('todos-list');
|
|
if (!todos.length) {
|
|
list.innerHTML = '<em>No todos yet.</em>';
|
|
return;
|
|
}
|
|
list.innerHTML = todos.map(todo => `
|
|
<div class="todo-item">
|
|
<div class="field"><b>ID:</b> ${todo.id}</div>
|
|
<div class="field"><b>Created:</b> ${todo.creationDate}</div>
|
|
<div class="field"><b>Next:</b> ${todo.nextDate || ''}</div>
|
|
<div class="field"><b>Due:</b> ${todo.dueDate || ''}</div>
|
|
<div class="field status-${todo.status || 'blank'}"><b>Status:</b> ${todo.status || ''}</div>
|
|
<div class="field urgent"><b>Urgent:</b> ${todo.urgent}</div>
|
|
<div class="field importance"><b>Importance:</b> ${todo.importance}</div>
|
|
<div class="field prio"><b>Prio:</b> ${todo.prio}</div>
|
|
<div class="field"><b>Est.:</b> ${todo.timeEstimation}m</div>
|
|
<div class="field"><b>Spent:</b> ${todo.actualTime}m</div>
|
|
<div class="field"><b>Category:</b> ${todo.category || ''}</div>
|
|
<div class="field"><b>Task:</b> ${todo.task}</div>
|
|
<div class="field"><b>Coms:</b> ${todo.coms ? `<a href="${todo.coms}" target="_blank">Link</a>` : ''}</div>
|
|
<div class="field"><b>Link:</b> ${todo.link ? `<a href="${todo.link}" target="_blank">Link</a>` : ''}</div>
|
|
<div class="field"><b>Comments:</b> ${todo.comments || ''}</div>
|
|
<div class="field"><b>Linked:</b> ${todo.linkedTasks || ''}</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
function addTodo(e) {
|
|
e.preventDefault();
|
|
const task = document.getElementById('task').value.trim();
|
|
const creationDate = document.getElementById('creation-date').value || new Date().toISOString().slice(0,10);
|
|
const nextDate = document.getElementById('next-date').value;
|
|
const dueDate = document.getElementById('due-date').value;
|
|
const status = document.getElementById('status').value;
|
|
const urgent = parseInt(document.getElementById('urgent').value) || 1;
|
|
const importance = parseInt(document.getElementById('importance').value) || 1;
|
|
const prio = urgent * importance;
|
|
const timeEstimation = parseInt(document.getElementById('time-estimation').value) || 0;
|
|
const actualTime = parseInt(document.getElementById('actual-time').value) || 0;
|
|
let category = document.getElementById('category').value.trim();
|
|
if (category && !categories.includes(category)) {
|
|
categories.push(category);
|
|
}
|
|
const coms = document.getElementById('coms').value.trim();
|
|
const link = document.getElementById('link').value.trim();
|
|
const comments = document.getElementById('comments').value.trim();
|
|
const linkedTasks = document.getElementById('linked-tasks').value.trim();
|
|
const todo = {
|
|
id: getNextId(),
|
|
creationDate,
|
|
nextDate,
|
|
dueDate,
|
|
status,
|
|
urgent,
|
|
importance,
|
|
prio,
|
|
timeEstimation,
|
|
actualTime,
|
|
category,
|
|
task,
|
|
coms,
|
|
link,
|
|
comments,
|
|
linkedTasks
|
|
};
|
|
todos.push(todo);
|
|
saveTodos();
|
|
renderForm();
|
|
renderTodos();
|
|
document.getElementById('todo-form').reset();
|
|
}
|
|
|
|
function init() {
|
|
loadTodos();
|
|
renderForm();
|
|
renderTodos();
|
|
document.getElementById('todo-form').addEventListener('submit', addTodo);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
|
|
// Password protection placeholder (to be implemented if needed)
|
|
// If you want to enable password, set a flag in localStorage and show/hide #password-section accordingly.
|