You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
11 KiB
305 lines
11 KiB
{{ template "base" . }} |
|
|
|
{{ define "content" }} |
|
|
|
<h1 style="display: none;" id="categoryId">{{.CurrentGroupId}}</h1> |
|
|
|
<!-- Main --> |
|
<main class="d-flex flex-wrap"> |
|
|
|
<!-- MODALS --> |
|
<!-- Delete Confirmation Modal --> |
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true"> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title" id="deleteModalLabel">Confirm Deletion</h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
|
</div> |
|
<div class="modal-body"> |
|
Are you sure you want to delete this ToDo? |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-danger" id="confirmDeleteButton">Delete</button> |
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<!-- End delete confirmation modal --> |
|
|
|
<!-- Paint Canvas Modal --> |
|
<div class="modal fade" id="paintModal" tabindex="-1" aria-labelledby="paintModal" aria-hidden="true"> |
|
<div class="modal-dialog"> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h5 class="modal-title" id="paintModal">Draw Note</h5> |
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" onclick="clearCanvas();"></button> |
|
</div> |
|
<div class="modal-body w-100 d-flex flex-column justify-content-center align-items-center"> |
|
{{ template "paint" . }} |
|
</div> |
|
<div class="modal-footer"> |
|
<button type="button" class="btn btn-primary" id="saveCanvasButton" data-bs-dismiss="modal">Save</button> |
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" onclick="clearCanvas();">Cancel</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
<!-- End Paint Canvas Modal --> |
|
|
|
|
|
<!-- Sidebar --> |
|
<div id="sidebar" class="col border-right shadow-lg flex-shrink-1 p-2 d-flex flex-column align-items-stretch bg-body-tertiary" style="width: 380px;"> |
|
<a href="/" class="d-flex align-items-center flex-shrink-0 p-3 link-body-emphasis text-decoration-none border-bottom"> |
|
<img class="bi pe-none me-2" width="30" height="24" src="/static/images/arrows-fullscreen.svg"> |
|
<span class="fs-5 fw-semibold">Categories</span> |
|
</a> |
|
|
|
<div class="list-group list-group-flush border-bottom scrollarea"> |
|
{{ range .Groups }} |
|
<a id="group-{{.ID}}" href="/group/{{.ID}}" class="list-group-item list-group-item-action py-3 lh-sm {{if eq .ID $.CurrentGroupId}} active {{end}}" aria-current="true" ondragover="allowDrop(event);" ondrop="drop(event);"> |
|
<div id="group-{{.ID}}" class="d-flex w-100 align-items-center justify-content-between"> |
|
<strong id="group-{{.ID}}" class="mb-1">{{ .Name }}</strong> |
|
<small id="group-{{.ID}}">{{ .TimeCreated }}</small> |
|
</div> |
|
{{ if not .Removable }} |
|
<div id="group-{{.ID}}" class="col-10 mb-1 small">Not removable</div> |
|
{{ end }} |
|
</a> |
|
{{ end }} |
|
</div> |
|
</div> |
|
|
|
|
|
|
|
<!-- Main ToDos section --> |
|
<div class="p-2 flex-grow-1"> |
|
<form action="javascript:void(0);"> |
|
<div class="container"> |
|
<div class="row"> |
|
<div class="col"> |
|
<input type="text" class="form-control" id="newTodoText" placeholder="TODO text"> |
|
</div> |
|
<div class="col"> |
|
<label for="newTodoDue">Due</label> |
|
<input aria-placeholder="Due" type="date" name="newTodoDue" id="newTodoDue" placeholder="Due"> |
|
</div> |
|
<div class="col"> |
|
<button class="btn btn-primary" id="newTodoPaint" onclick="openPaintModal();">Paint</button> |
|
</div> |
|
<div class="col"> |
|
<button id="newTodoSubmit" class="btn btn-primary">Add</button> |
|
<button class="btn btn-secondary" id="show-done">Show Done</button> |
|
</div> |
|
</div> |
|
</div> |
|
</form> |
|
|
|
<div class="container text-center"> |
|
<!-- Due --> |
|
<table class="table table-hover" id="due-todos"> |
|
<thead> |
|
<th>Image</th> |
|
<th>ToDo</th> |
|
<th>Created</th> |
|
<th>Due</th> |
|
</thead> |
|
<tbody class="text-break"> |
|
{{ range .Todos }} |
|
{{ if not .IsDone }} |
|
<tr draggable="true" id="todo-{{.ID}}" ondragstart="dragStart(event);"> |
|
{{ if not .Image }} |
|
<!-- Display transparent white pixel --> |
|
<td><img class="todo-image" src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' width="64px" height="64px"></td> |
|
{{ else }} |
|
<td><img class="todo-image" src='{{ printf "%s" .Image }}' width="64px" height="64px"></td> |
|
{{ end }} |
|
<td class="todo-text text-wrap text-break">{{ .Text }}</td> |
|
<td class="todo-created">{{ .TimeCreated }}</td> |
|
<td class="todo-due">{{ .Due }}</td> |
|
<td class="todo-due-unix" style="display: none;">{{ .DueUnix }}</td> |
|
<td> |
|
<button class="btn btn-success" onclick="markAsDoneRefresh('{{.ID}}');"> |
|
<img src='/static/images/check.svg'> |
|
</button> |
|
<button class="btn btn-danger" onclick="openDeleteModal('{{.ID}}');"> |
|
<img src='/static/images/trash3-fill.svg'> |
|
</button> |
|
</td> |
|
</tr> |
|
{{ end }} |
|
{{ end }} |
|
</tbody> |
|
</table> |
|
|
|
<!-- Completed --> |
|
<table class="table table-hover" style="display: none;" id="completed-todos"> |
|
<thead> |
|
<th>Image</th> |
|
<th>ToDo</th> |
|
<th>Created</th> |
|
<th>Completed</th> |
|
</thead> |
|
<tbody class="text-break"> |
|
{{ range .Todos }} |
|
{{ if .IsDone }} |
|
<tr> |
|
{{ if not .Image }} |
|
<!-- Display transparent white pixel --> |
|
<td><img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' width="64px" height="64px"></td> |
|
{{ else }} |
|
<td><img src='{{ printf "%s" .Image }}' width="64px" height="64px"></td> |
|
{{ end }} |
|
<td>{{ .Text }}</td> |
|
<td>{{ .TimeCreated }}</td> |
|
<td>{{ .CompletionTime }}</td> |
|
<td> |
|
<button class="btn btn-danger" onclick="deleteTodoRefresh('{{.ID}}');"><img src='/static/images/trash3-fill.svg'></button> |
|
</td> |
|
</tr> |
|
{{ end }} |
|
{{ end }} |
|
</tbody> |
|
</table> |
|
</div> |
|
</div> |
|
</main> |
|
|
|
|
|
<script> |
|
let todoToDeleteId; |
|
|
|
// TODO deletion modal functions |
|
function openDeleteModal(id) { |
|
todoToDeleteId = id; // Save ID for handleTodoDelete to work properly |
|
|
|
const deleteModal = new bootstrap.Modal(document.getElementById('deleteModal'), {}); |
|
|
|
// Remove any existing event listener to prevent multiple bindings |
|
const confirmDeleteButton = document.getElementById('confirmDeleteButton'); |
|
confirmDeleteButton.removeEventListener('click', handleTodoDelete); |
|
|
|
// Add the event listener for the delete action |
|
confirmDeleteButton.addEventListener('click', handleTodoDelete); |
|
|
|
deleteModal.show(); |
|
} |
|
|
|
async function handleTodoDelete() { |
|
await deleteTodoRefresh(todoToDeleteId); // Call the delete function |
|
const deleteModal = bootstrap.Modal.getInstance(document.getElementById('deleteModal')); |
|
deleteModal.hide(); // Hide the modal |
|
} |
|
|
|
|
|
function openPaintModal() { |
|
const paintModal = new bootstrap.Modal(document.getElementById('paintModal'), {});; |
|
paintModal.show(); |
|
} |
|
|
|
// Mark TODO as done |
|
async function markAsDoneRefresh(id) { |
|
await markAsDone(id); |
|
window.location.reload(); |
|
} |
|
|
|
// Delete TODO with ID |
|
async function deleteTodoRefresh(id) { |
|
await deleteTodo(id); |
|
window.location.reload(); |
|
} |
|
|
|
async function showDone() { |
|
// Hide not done, show done |
|
let completedTodos = document.getElementById("completed-todos"); |
|
completedTodos.style.display = "table"; |
|
|
|
let dueTodos = document.getElementById("due-todos"); |
|
dueTodos.style.display = "none"; |
|
} |
|
|
|
function allowDrop(event) { |
|
event.preventDefault(); |
|
} |
|
|
|
function dragStart(event) { |
|
event.dataTransfer.setData("text", event.target.id); |
|
event.dataTransfer.effectAllowed = "move"; |
|
} |
|
|
|
async function drop(event) { |
|
event.preventDefault(); |
|
|
|
var todoPageId = event.dataTransfer.getData("text"); |
|
let draggedTodo = document.getElementById(todoPageId); |
|
let todoId = todoPageId.split("-")[1]; |
|
let targetGroupId = event.target.id.split("-")[1]; |
|
if (targetGroupId == document.getElementById("categoryId").innerText) { |
|
// Do nothing |
|
return; |
|
} |
|
|
|
// Update todo's group ID |
|
let result = await updateTodo(todoId, { |
|
text: draggedTodo.getElementsByClassName("todo-text")[0].innerText, |
|
groupId: Number(targetGroupId), |
|
dueUnix: Number(draggedTodo.getElementsByClassName("todo-due-unix")[0].innerText), |
|
image: Array.from(draggedTodo.getElementsByClassName("todo-image")[0].src, char => char.charCodeAt(0)) |
|
}); |
|
|
|
window.location.reload(); |
|
} |
|
|
|
document.addEventListener('DOMContentLoaded', async function() { |
|
document.getElementById("newTodoText").focus(); |
|
|
|
let showDoneButton = document.getElementById("show-done"); |
|
showDoneButton.addEventListener("click", (event) => { |
|
// Rename the button |
|
showDoneButton.innerText = "Show To Do"; |
|
showDoneButton.className = "btn btn-success"; |
|
// Show done |
|
showDone(); |
|
|
|
// Make it "reset to default" |
|
showDoneButton.addEventListener("click", (event) => { |
|
location.reload(); |
|
}); |
|
}); |
|
|
|
|
|
// "Add" button |
|
document.getElementById("newTodoSubmit").addEventListener("click", async (event) => { |
|
let newTodoTextInput = document.getElementById("newTodoText"); |
|
let newTodoText = newTodoTextInput.value; |
|
if (newTodoText.length < 1) { |
|
newTodoTextInput.setCustomValidity("At least one character is needed!"); |
|
return; |
|
} else { |
|
newTodoTextInput.setCustomValidity(""); |
|
} |
|
newTodoTextInput.value = ""; |
|
|
|
let newTodoDueInput = document.getElementById("newTodoDue"); |
|
let dueTimeStamp = Date.parse(newTodoDueInput.value) / 1000; |
|
|
|
let groupId = document.getElementById("categoryId").innerText; |
|
|
|
let canvasImage = getCanvasImage(); |
|
if (canvasImage) { |
|
canvasImage = Array.from(canvasImage, char => char.charCodeAt(0)); |
|
} |
|
|
|
// Make a request |
|
let response = await postNewTodo( |
|
{text: newTodoText, groupId: Number(groupId), dueUnix: Number(dueTimeStamp), image: canvasImage} |
|
); |
|
if (response.ok) { |
|
location.reload(); |
|
} |
|
}); |
|
}); |
|
</script> |
|
|
|
{{ end }} |