199 lines
5.7 KiB
JavaScript
199 lines
5.7 KiB
JavaScript
// Enable debug mode if the URL contains the debug parameter
|
|
let debug = false;
|
|
if (window.location.href.includes('debug')) {
|
|
console.log('Debug mode enabled');
|
|
debug = true;
|
|
}
|
|
|
|
// Initialize the EventSource and the HTML elements
|
|
const eventSource = new EventSource('https://ntfy.example.org/guestbook/sse?since=all');
|
|
const entryText = document.getElementById('entryText');
|
|
const name = document.getElementById('name');
|
|
const submitEntry = document.getElementById('submitEntry');
|
|
const entryTable = document.getElementById('entryTable');
|
|
const errorMessage = document.getElementById('error-message');
|
|
const bell = new Audio('/resources/sounds/notification.ogg');
|
|
|
|
// Disable the notification sound for the first 2 seconds until the guestbook is loaded initially
|
|
let bellEnabled = false;
|
|
|
|
// Event listener for the Enter key
|
|
function handleKeydown(event) {
|
|
if (event.key === 'Enter') {
|
|
sendMessage();
|
|
}
|
|
}
|
|
|
|
// Check if the name is valid
|
|
function checkName(name) {
|
|
if (name.match(/:\s/)) {
|
|
errorMessage.classList.add('visible');
|
|
console.error('Invalid name');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Send new entry to the ntfy server
|
|
function sendMessage() {
|
|
const text = entryText.value.trim();
|
|
const author = name.value.trim() ? name.value.trim() : 'Anonymous';
|
|
if (checkName(author)) {
|
|
errorMessage.classList.remove('visible');
|
|
const message = author + ': ' + text;
|
|
if (text.length > 0) {
|
|
fetch('https://ntfy.example.org/guestbook', {
|
|
method: 'POST',
|
|
body: message
|
|
})
|
|
.then(() => {
|
|
// Empty the input field
|
|
entryText.value = '';
|
|
// Save the name in the local storage
|
|
localStorage.setItem('name', author);
|
|
})
|
|
.catch(error => console.error(error));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate time passed since the message was sent
|
|
function timeSince(date) {
|
|
let seconds = Math.floor(Date.now() / 1000 - date);
|
|
let interval = Math.floor(seconds / 3600);
|
|
if (interval >= 2) {
|
|
return interval + " hours ago";
|
|
}
|
|
if (interval === 1) {
|
|
return "1 hour ago"
|
|
}
|
|
interval = Math.floor(seconds / 60);
|
|
if (interval > 1) {
|
|
return interval + " minutes ago";
|
|
}
|
|
if (interval === 1) {
|
|
return "1 minute ago"
|
|
}
|
|
if (seconds > 10) {
|
|
return Math.floor(seconds) + " seconds ago";
|
|
}
|
|
if (seconds > -10) {
|
|
return "just now"
|
|
}
|
|
if (seconds > -60) {
|
|
return "in " + Math.floor(-seconds) + " seconds";
|
|
}
|
|
interval = Math.floor(-seconds / 60);
|
|
if (interval === 1) {
|
|
return "in 1 minute";
|
|
}
|
|
if (interval < 60) {
|
|
return "in " + interval + " minutes";
|
|
}
|
|
interval = Math.floor(-seconds / 3600);
|
|
if (interval === 1) {
|
|
return "in 1 hour";
|
|
}
|
|
if (interval > 1) {
|
|
return "in " + interval + " hours";
|
|
}
|
|
}
|
|
|
|
// Parse the time from the message
|
|
function parseTimeString(data) {
|
|
return ` | ${timeSince(data.time)}, expires in ${timeSince(data.expires)}`
|
|
}
|
|
|
|
// Update time
|
|
function updateTime() {
|
|
const timeElements = document.getElementsByClassName('time');
|
|
for (let i = 0; i < timeElements.length; i++) {
|
|
const time = timeElements[i];
|
|
time.textContent = parseTimeString(time.dataset);
|
|
}
|
|
}
|
|
|
|
// Add a new entry to the list
|
|
function addEntry(data) {
|
|
const row = document.createElement('tr');
|
|
|
|
// Create a new cell for the author
|
|
const authorCell = document.createElement('td');
|
|
authorCell.classList.add('author');
|
|
authorCell.style.fontWeight = 'italic';
|
|
|
|
// Create a new cell for the message
|
|
const messageCell = document.createElement('td');
|
|
messageCell.classList.add('message');
|
|
|
|
// Split the message into author and text
|
|
const [name, message] = data.message.split(/:\s(.*)/);
|
|
|
|
// Create span with the time that passed since the message was sent
|
|
// and when the message will expire
|
|
const time = document.createElement('span');
|
|
time.classList.add('time');
|
|
time.dataset.time = data.time;
|
|
time.dataset.expires = data.expires;
|
|
time.textContent = parseTimeString(data);
|
|
|
|
// Set the cell content
|
|
authorCell.textContent = name + ':';
|
|
messageCell.innerHTML = message + time.outerHTML;
|
|
|
|
// Append the cells to the row and the row to the table
|
|
row.appendChild(authorCell);
|
|
row.appendChild(messageCell);
|
|
|
|
entryTable.appendChild(row);
|
|
}
|
|
|
|
// Connect to the server to receive new entries
|
|
function streamEntries() {
|
|
eventSource.onmessage = (m) => {
|
|
if (debug) {
|
|
console.log(m.data);
|
|
}
|
|
const data = JSON.parse(m.data)
|
|
addEntry(data);
|
|
|
|
// Play a notification sound for new entries
|
|
try {
|
|
if (bellEnabled) {
|
|
bell.play();
|
|
}
|
|
} catch (DOMException) {
|
|
console.log('The notification sound was blocked by the browser');
|
|
}
|
|
};
|
|
}
|
|
|
|
// Initialize the page
|
|
function setup() {
|
|
// Add event listeners
|
|
submitEntry.addEventListener('click', sendMessage);
|
|
entryText.addEventListener('keydown', handleKeydown);
|
|
|
|
// Start streaming the entries
|
|
streamEntries();
|
|
|
|
// Update the time values every 10 seconds
|
|
setInterval(updateTime, 10000);
|
|
|
|
// Load the name from the local storage
|
|
name.value = localStorage.getItem('name');
|
|
|
|
// Enable the notification sound after 2 seconds
|
|
setTimeout(() => {
|
|
bellEnabled = true;
|
|
}, 2000);
|
|
|
|
// Close the connection when the page is closed
|
|
window.addEventListener('beforeunload', function (e) {
|
|
e.preventDefault();
|
|
eventSource.close();
|
|
});
|
|
}
|
|
|
|
window.addEventListener('load', setup)
|