changes
This commit is contained in:
parent
9e931243ef
commit
c6b6021fa9
@ -224,6 +224,21 @@ body {
|
|||||||
transition: opacity 0.3s;
|
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 {
|
.message:hover .delete-button {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@ -232,6 +247,10 @@ body {
|
|||||||
background: var(--timestamp-color);
|
background: var(--timestamp-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-button:hover {
|
||||||
|
background: var(--timestamp-color);
|
||||||
|
}
|
||||||
|
|
||||||
.settings-icon, .users-icon, .theme-icon{
|
.settings-icon, .users-icon, .theme-icon{
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
@ -537,6 +556,11 @@ button.scroll:hover {
|
|||||||
opacity: 1; /* Always visible on mobile */
|
opacity: 1; /* Always visible on mobile */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
padding: 8px 12px;
|
||||||
|
opacity: 1; /* Always visible on mobile */
|
||||||
|
}
|
||||||
|
|
||||||
@media (orientation: landscape) {
|
@media (orientation: landscape) {
|
||||||
.messages-section {
|
.messages-section {
|
||||||
margin-top: 45px;
|
margin-top: 45px;
|
||||||
|
@ -27,6 +27,41 @@ function toggleTheme() {
|
|||||||
localStorage.setItem("theme", newTheme);
|
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) {
|
async function deleteMessage(messageId) {
|
||||||
if (confirm("Delete this message?")) {
|
if (confirm("Delete this message?")) {
|
||||||
try {
|
try {
|
||||||
@ -201,12 +236,24 @@ async function loadMessages(forceUpdate = false, scrollLocation) {
|
|||||||
);
|
);
|
||||||
usernameDiv.innerHTML = username;
|
usernameDiv.innerHTML = username;
|
||||||
compareUsername = usernameDiv.textContent;
|
compareUsername = usernameDiv.textContent;
|
||||||
let deleteHtml = "";
|
|
||||||
|
|
||||||
const embeddedContent = contentEmbedding(
|
const embeddedContent = contentEmbedding(
|
||||||
content,
|
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 (
|
if (
|
||||||
compareUsername ===
|
compareUsername ===
|
||||||
document.getElementById(
|
document.getElementById(
|
||||||
@ -215,10 +262,12 @@ async function loadMessages(forceUpdate = false, scrollLocation) {
|
|||||||
) {
|
) {
|
||||||
deleteHtml =
|
deleteHtml =
|
||||||
`<button class="delete-button" title="Delete message" onclick="deleteMessage('${messageId}')" style="display: inline;">🗑️</button>`;
|
`<button class="delete-button" title="Delete message" onclick="deleteMessage('${messageId}')" style="display: inline;">🗑️</button>`;
|
||||||
|
editHtml =
|
||||||
|
`<button class="edit-button" title="Edit message" onclick="editMessage('${messageId}', '${contentString}')" style="display: inline;">📝</button>`;
|
||||||
}
|
}
|
||||||
messageDiv.innerHTML = `
|
messageDiv.innerHTML = `
|
||||||
<div class="message-header">
|
<div class="message-header">
|
||||||
<div class="username">${username} ${timestamp} ${deleteHtml}</div>
|
<div class="username">${username} ${timestamp} ${deleteHtml} ${editHtml}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">${embeddedContent}</div>`;
|
<div class="content">${embeddedContent}</div>`;
|
||||||
|
|
||||||
|
36
main.go
36
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) {
|
func (db *Database) DeleteOldMessages(ageMinutes int) {
|
||||||
if ageMinutes <= 0 {
|
if ageMinutes <= 0 {
|
||||||
return
|
return
|
||||||
@ -474,6 +486,30 @@ func getMessageTemplate(filepath string, body string) string {
|
|||||||
|
|
||||||
func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleMessages(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
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:
|
case http.MethodGet:
|
||||||
w.Header().Set("Content-Type", "text/html")
|
w.Header().Set("Content-Type", "text/html")
|
||||||
|
|
||||||
|
@ -7,11 +7,10 @@
|
|||||||
### Low Priority
|
### Low Priority
|
||||||
- Reposition the search button
|
- Reposition the search button
|
||||||
- Fix mobile views instead of hiding elements that you don't want to position properly
|
- Fix mobile views instead of hiding elements that you don't want to position properly
|
||||||
- Ability to edit messages
|
|
||||||
## Backend
|
## Backend
|
||||||
### High Priority
|
### High Priority
|
||||||
- Lazy load with pagination (frontend and backend)
|
- Lazy load with pagination (frontend and backend)
|
||||||
### Mid Priority
|
### Mid Priority
|
||||||
- Nothing yet
|
- Nothing yet
|
||||||
### Low Priority
|
### Low Priority
|
||||||
- Ability to edit messages
|
- Nothing yet
|
||||||
|
Loading…
x
Reference in New Issue
Block a user