diff --git a/pages/category.html b/pages/category.html
index bd6a49a..0fbea35 100644
--- a/pages/category.html
+++ b/pages/category.html
@@ -57,14 +57,28 @@
-
Text:
-
Created:
-
Due:
-
Completion time:
-
+
+ Text:
+
+
+
+
+ Created:
+
+
+ Due:
+
+
+
+
+ Completion time:
+
+
@@ -128,7 +142,7 @@
{{ range .Todos }}
{{ if not .IsDone }}
-
+
{{ if not .Image }}
|
@@ -164,7 +178,7 @@
{{ range .Todos }}
{{ if .IsDone }}
-
+
{{ if not .Image }}
|
@@ -262,19 +276,22 @@ async function drop(event) {
// 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();
}
-function openTodoModal(id, text, created, due, completionTime, image) {
- document.getElementById('modalTodoText').innerText = text;
+
+let viewedTodoID;
+function openTodoModal(id, text, created, due, completionTime, image, editable) {
+ viewedTodoID = id;
+
+ document.getElementById('modalTodoTextDisplay').innerText = text;
+ document.getElementById('modalTodoTextInput').value = text;
document.getElementById('modalTodoCreated').innerText = created;
- document.getElementById('modalTodoDue').innerText = due;
+ document.getElementById('modalTodoDueDisplay').innerText = due;
+ document.getElementById('modalTodoDueInput').value = due;
document.getElementById('modalTodoCompletionTime').innerText = completionTime;
let img = document.getElementById('modalTodoImage');
@@ -285,10 +302,42 @@ function openTodoModal(id, text, created, due, completionTime, image) {
img.style.display = 'none';
}
+ let editButton = document.getElementById("editButton");
+ if (editable) {
+ // Show "Edit" button
+ editButton.style.display = "inline";
+ } else {
+ editButton.style.display = "none";
+ }
+
const todoModal = new bootstrap.Modal(document.getElementById('todoModal'));
todoModal.show();
}
+async function saveEditedTodo() {
+ const updatedText = document.getElementById('modalTodoTextInput').value;
+ const updatedDue = document.getElementById('modalTodoDueInput').value;
+ document.getElementById('modalTodoTextDisplay').innerText = updatedText;
+ document.getElementById('modalTodoDueDisplay').innerText = updatedDue;
+ const updatedDueUnix = Date.parse(updatedDue) / 1000;
+
+ toggleEditMode(false);
+
+ await updateTodo(viewedTodoID, {"text":updatedText, "dueUnix":updatedDueUnix, "isDone":false});
+
+ window.location.reload();
+}
+
+
+function toggleEditMode(isEditing) {
+ document.getElementById('modalTodoTextDisplay').style.display = isEditing ? 'none' : 'inline';
+ document.getElementById('modalTodoTextInput').style.display = isEditing ? 'inline' : 'none';
+ document.getElementById('modalTodoDueDisplay').style.display = isEditing ? 'none' : 'inline';
+ document.getElementById('modalTodoDueInput').style.display = isEditing ? 'inline' : 'none';
+ document.getElementById('editButton').style.display = isEditing ? 'none' : 'inline';
+ document.getElementById('saveButton').style.display = isEditing ? 'inline' : 'none';
+}
+
document.addEventListener('DOMContentLoaded', async function() {
document.getElementById("newTodoText").focus();
@@ -331,7 +380,7 @@ document.addEventListener('DOMContentLoaded', async function() {
// Make a request
let response = await postNewTodo(
- {text: newTodoText, groupId: Number(groupId), dueUnix: Number(dueTimeStamp), image: canvasImage}
+ {"text": newTodoText, "groupId": Number(groupId), "dueUnix": Number(dueTimeStamp), "image": canvasImage}
);
if (response.ok) {
location.reload();
diff --git a/src/db/todo.go b/src/db/todo.go
index 0527889..cef986a 100644
--- a/src/db/todo.go
+++ b/src/db/todo.go
@@ -19,7 +19,9 @@
package db
import (
+ "bytes"
"database/sql"
+ "strings"
"time"
)
@@ -157,6 +159,52 @@ func (db *DB) UpdateTodo(todoID uint64, updatedTodo Todo) error {
return err
}
+// Updates all changed fields which are not nil-valued in a ToDo and retains all unchanged ones
+func (db *DB) UpdateTodoSoft(todoID uint64, updatedTodo Todo) error {
+ originalTodo, err := db.GetTodo(todoID)
+ if err != nil {
+ return err
+ }
+
+ args := []interface{}{}
+ updates := []string{}
+ if (updatedTodo.GroupID != originalTodo.GroupID) && updatedTodo.GroupID != 0 {
+ updates = append(updates, "group_id=?")
+ args = append(args, updatedTodo.GroupID)
+ }
+ if (updatedTodo.DueUnix != originalTodo.DueUnix) && updatedTodo.DueUnix != 0 {
+ updates = append(updates, "due_unix=?")
+ args = append(args, updatedTodo.DueUnix)
+ }
+ if (updatedTodo.Text != originalTodo.Text) && updatedTodo.Text != "" {
+ updates = append(updates, "text=?")
+ args = append(args, updatedTodo.Text)
+ }
+ if updatedTodo.IsDone != originalTodo.IsDone {
+ updates = append(updates, "is_done=?")
+ args = append(args, updatedTodo.IsDone)
+ }
+ if (updatedTodo.CompletionTimeUnix != originalTodo.CompletionTimeUnix) && updatedTodo.CompletionTimeUnix != 0 {
+ updates = append(updates, "completion_time_unix=?")
+ args = append(args, updatedTodo.CompletionTimeUnix)
+ }
+ if !bytes.Equal(updatedTodo.Image, originalTodo.Image) && updatedTodo.Image != nil {
+ updates = append(updates, "image=?")
+ args = append(args, updatedTodo.Image)
+ }
+
+ if len(updates) == 0 {
+ return nil
+ }
+
+ query := "UPDATE todos SET " + strings.Join(updates, ", ") + " WHERE id=?"
+ args = append(args, todoID)
+
+ _, err = db.Exec(query, args...)
+
+ return err
+}
+
// Searches and retrieves TODO groups created by the user
func (db *DB) GetAllUserTodoGroups(email string) ([]*TodoGroup, error) {
var todoGroups []*TodoGroup
diff --git a/src/db/verification.go b/src/db/verification.go
index acd1db7..37eec69 100644
--- a/src/db/verification.go
+++ b/src/db/verification.go
@@ -8,8 +8,8 @@ type Verification struct {
ID uint64 `json:"id"`
Email string `json:"email"`
Code string `json:"code"`
- IssuedUnix uint64 `json:"issued_unix"`
- LifeSeconds uint64 `json:"life_seconds"`
+ IssuedUnix uint64 `json:"issuedUnix"`
+ LifeSeconds uint64 `json:"lifeSeconds"`
}
func NewVerification(email string, code string, issuedUnix uint64, lifeSeconds uint64) *Verification {
diff --git a/src/server/endpoints.go b/src/server/endpoints.go
index 34dd59f..aa1e220 100644
--- a/src/server/endpoints.go
+++ b/src/server/endpoints.go
@@ -421,8 +421,8 @@ func (s *Server) EndpointTodoUpdate(w http.ResponseWriter, req *http.Request) {
return
}
- // Update. (Creation date, owner username and an ID do not change)
- err = s.db.UpdateTodo(todoID, updatedTodo)
+ // Update
+ err = s.db.UpdateTodoSoft(todoID, updatedTodo)
if err != nil {
logger.Warning("[Server] Failed to update TODO: %s", err)
http.Error(w, "Failed to update", http.StatusBadRequest)