diff --git a/content/root.css b/content/root.css index ec90449..0a1285c 100644 --- a/content/root.css +++ b/content/root.css @@ -224,6 +224,21 @@ body { transition: opacity 0.3s; } +.edit-button { + background: none; + border: none; + cursor: pointer; + color: var(--timestamp-color); + padding: 2px 6px; + font-size: 12px; + opacity: 0; + transition: opacity 0.3s; +} + +.message:hover .edit-button { + opacity: 1; +} + .message:hover .delete-button { opacity: 1; } @@ -232,6 +247,10 @@ body { background: var(--timestamp-color); } +.edit-button:hover { + background: var(--timestamp-color); +} + .settings-icon, .users-icon, .theme-icon{ width: 24px; height: 24px; @@ -537,6 +556,11 @@ button.scroll:hover { opacity: 1; /* Always visible on mobile */ } + .edit-button { + padding: 8px 12px; + opacity: 1; /* Always visible on mobile */ + } + @media (orientation: landscape) { .messages-section { margin-top: 45px; diff --git a/content/root.js b/content/root.js index ff261e1..e5ec7cb 100644 --- a/content/root.js +++ b/content/root.js @@ -27,6 +27,41 @@ function toggleTheme() { localStorage.setItem("theme", newTheme); } +async function editMessage(messageId, content) { + const newContent = prompt("Edit message:", content); + if (newContent === null) { + return; + } + if (newContent === "") { + deleteMessage(messageId); + return; + } + if (newContent === content) { + return; + } + + try { + const response = await fetch("/messages", { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + messageId: messageId, + messageContent: newContent, + }), + }); + + if (response.ok) { + updateMessagesInPlace(); + } else { + console.error("Failed to edit message"); + } + } catch (error) { + console.error("Error editing message:", error); + } +} + async function deleteMessage(messageId) { if (confirm("Delete this message?")) { try { @@ -201,12 +236,24 @@ async function loadMessages(forceUpdate = false, scrollLocation) { ); usernameDiv.innerHTML = username; compareUsername = usernameDiv.textContent; - let deleteHtml = ""; const embeddedContent = contentEmbedding( content, ); + let deleteHtml = ""; + let editHtml = ""; + + const parser = new DOMParser(); + const contentHtmlString = content; + const doc = parser.parseFromString( + contentHtmlString, + "text/html", + ); + const contentString = + doc.querySelector("span").textContent; + console.log(contentString); + if ( compareUsername === document.getElementById( @@ -215,10 +262,12 @@ async function loadMessages(forceUpdate = false, scrollLocation) { ) { deleteHtml = ``; + editHtml = + ``; } messageDiv.innerHTML = `
-
${username} ${timestamp} ${deleteHtml}
+
${username} ${timestamp} ${deleteHtml} ${editHtml}
${embeddedContent}
`; diff --git a/main.go b/main.go index 1984d3a..b7273d4 100644 --- a/main.go +++ b/main.go @@ -281,6 +281,18 @@ func (db *Database) MessageDeleteIfOwner(id string, ip string) (int, error) { } +func (db *Database) MessageEditIfOwner(id string, content string, ip string) (int, error) { + res, err := db.db.Exec("UPDATE messages SET content = ? WHERE id = ? AND ip_address = ?", content, id, ip) + if err != nil { + return 0, err + } + affected, err := res.RowsAffected() + if err != nil { + return 0, err + } + return int(affected), nil +} + func (db *Database) DeleteOldMessages(ageMinutes int) { if ageMinutes <= 0 { return @@ -474,6 +486,30 @@ func getMessageTemplate(filepath string, body string) string { func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) { switch r.Method { + case http.MethodPatch: + w.Header().Set("Content-Type", "application/json") + var req struct { + MessageId string `json:"messageId"` + MessageContent string `json:"messageContent"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, `{"error": "Invalid JSON"}`, http.StatusBadRequest) + return + } + + clientIP := getClientIP(r) + if affected, err := s.Database.MessageEditIfOwner(req.MessageId, req.MessageContent, clientIP); err != nil { + http.Error(w, `{"error": "Unauthorized"}`, http.StatusNotFound) + return + } else if affected == 0 { + http.Error(w, `{"error": "Message not found"}`, http.StatusNotFound) + return + } + + json.NewEncoder(w).Encode(map[string]string{ + "status": "Message edited successfully", + }) + case http.MethodGet: w.Header().Set("Content-Type", "text/html") diff --git a/readme.md b/readme.md index f0e6979..23ea664 100644 --- a/readme.md +++ b/readme.md @@ -7,11 +7,10 @@ ### Low Priority - Reposition the search button - Fix mobile views instead of hiding elements that you don't want to position properly -- Ability to edit messages ## Backend ### High Priority - Lazy load with pagination (frontend and backend) ### Mid Priority - Nothing yet ### Low Priority -- Ability to edit messages +- Nothing yet