I have created a piece of code that works with a JSON file to store table data, one of the things the user can do when adding entries is set the rank of their entry. Say we have 5 entries:
Rank = 1 (A),2 (B),3 (C),4 (D),5 (E) respectively then they add an entry with Rank = 18 it should automatically become Rank = 6 (F) to follow the sequential order. Now alternatively if they now edit an existing entry (F) with Rank = 6 and edit its rank to become 1 then the new order should be:
Rank = 1 (F)
Rank = 2 (A)
Rank = 3 (B)
Rank = 4 (C)
Rank = 5 (D)
Rank = 6 (E)
But in my implementation this behavior is not observed instead the ranks don’t seem to swap at all.
This is my current code that I am working on:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mowie Ranking</title>
<style>
:root {
--background-color: #1c1c1c;
--text-color: #f4f4f4;
--header-background: #e67e22;
--header-border: #d35400;
--container-background: #333;
--textarea-background: #2c2c2c;
--border-color: #e67e22;
--status-text-color: #f1c40f;
--saved-text-color: #e74c3c;
--scrollbar-thumb: #e67e22;
--scrollbar-track: #333;
--button-background: #d35400;
--button-text-color: #fff;
--button-border-color: #e67e22;
--button-hover-background: #e67e22;
--button-hover-text-color: #fff;
--button-delete-background: #c0392b;
--button-delete-text-color: #fff;
--button-delete-hover-background: #e74c3c;
--button-delete-hover-text-color: #fff;
--input-background: #2c2c2c;
--input-border-color: #e67e22;
--input-text-color: #fff;
}
body {
font-family: "Arial", sans-serif;
margin: 0;
padding: 0;
background: var(--background-color);
color: var(--text-color);
text-align: center;
}
header {
background-color: var(--header-background);
color: #fff;
padding: 20px;
font-size: 2.5em;
border-bottom: 3px solid var(--header-border);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
z-index: 1;
}
header::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url("https://www.example.com/halloween-pattern.png")
no-repeat center center;
background-size: cover;
opacity: 0.2;
z-index: -1;
}
.container {
max-width: 800px;
margin: 40px auto;
padding: 20px;
background: var(--container-background);
border-radius: 12px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
overflow: hidden;
text-align: left;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th,
td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: center;
}
th {
background-color: var(--header-background);
color: #fff;
}
td input {
width: 100%;
box-sizing: border-box;
background-color: var(--input-background);
border: 1px solid var(--input-border-color);
color: var(--input-text-color);
padding: 8px;
border-radius: 4px;
}
.add-entry {
margin-bottom: 20px;
}
.add-entry input,
.add-entry button {
margin: 5px 0;
padding: 10px;
border-radius: 6px;
border: 1px solid var(--button-border-color);
background-color: var(--input-background);
color: var(--input-text-color);
}
.add-entry button {
background-color: var(--button-background);
color: var(--button-text-color);
cursor: pointer;
transition: background-color 0.3s ease, border-color 0.3s ease;
}
.add-entry button:hover {
background-color: var(--button-hover-background);
border-color: var(--button-hover-background);
}
.delete-btn {
background-color: var(--button-delete-background);
color: var(--button-delete-text-color);
border: none;
padding: 5px 10px;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.delete-btn:hover {
background-color: var(--button-delete-hover-background);
color: var(--button-delete-text-color);
}
::-webkit-scrollbar {
width: 12px;
}
::-webkit-scrollbar-track {
background: var(--scrollbar-track);
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
background: var(--scrollbar-thumb);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: #d35400;
}
body {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.actions-column {
width: 60px;
}
.mowie-column {
width: calc(100% - 160px);
}
th,
td {
text-align: center;
}
</style>
</head>
<body>
<header>Mowie Ranking</header>
<div class="container">
<div class="add-entry">
<input type="number" id="rank" placeholder="Rank" min="1" />
<input type="text" id="mowie" placeholder="Mowie Name" />
<input
type="number"
id="rating"
placeholder="Rating (1-10)"
min="1"
max="10"
/>
<input type="text" id="genre" placeholder="Genre" />
<button id="add-entry">Add Entry</button>
</div>
<table>
<thead>
<tr>
<th class="actions-column">Actions</th>
<th>Rank</th>
<th class="mowie-column">Mowie</th>
<th>Rating</th>
<th>Genre</th>
</tr>
</thead>
<tbody id="table-body">
<!-- Table rows will be dynamically inserted here -->
</tbody>
</table>
</div>
<script>
const autosaveDelay = 1000; // Autosave delay in milliseconds
const tableBody = document.getElementById("table-body");
// WebSocket connection
const socket = new WebSocket(`wss://${window.location.host}`);
socket.addEventListener("open", function () {
console.log("WebSocket is connected.");
});
socket.addEventListener("message", function (event) {
if (event.data instanceof Blob) {
const reader = new FileReader();
reader.onload = function () {
const data = JSON.parse(reader.result);
updateTable(data);
};
reader.readAsText(event.data);
} else {
const data = JSON.parse(event.data);
updateTable(data);
}
});
// Add new entry
document
.getElementById("add-entry")
.addEventListener("click", function () {
const rank = parseInt(document.getElementById("rank").value, 10);
const mowie = document.getElementById("mowie").value;
const rating = document.getElementById("rating").value + "/10";
const genre = document.getElementById("genre").value;
if (mowie && rating && genre) {
let nextRank = rank || tableBody.rows.length + 1;
if (rank) {
// Adjust ranks if a rank is provided
const rows = Array.from(tableBody.rows);
rows.forEach((row) => {
const currentRank = parseInt(row.cells[1].innerText, 10);
if (currentRank >= rank) {
row.cells[1].innerText = currentRank + 1;
}
});
}
const row = tableBody.insertRow();
row.insertCell(0).innerHTML =
'<button class="delete-btn">Delete</button>';
row.insertCell(1).innerText = nextRank; // Assign rank
row.insertCell(2).innerText = mowie;
row.insertCell(3).innerText = rating;
row.insertCell(4).innerText = genre;
updateAndSave(); // Save the new entry
document.getElementById("rank").value = "";
document.getElementById("mowie").value = "";
document.getElementById("rating").value = "";
document.getElementById("genre").value = "";
}
});
// Update and save function
function updateAndSave() {
const rows = Array.from(tableBody.rows);
updateTable(updatedData);
// Create an array to hold the updated data
const updatedData = rows.map((row, index) => ({
rank: index + 1, // Assign sequential ranks starting from 1
mowie: row.cells[2].innerText,
rating: row.cells[3].innerText,
genre: row.cells[4].innerText,
}));
// Update the table with new ranks
rows.forEach((row, index) => {
row.cells[1].innerText = updatedData[index].rank;
});
// Send updated data to the server
fetch(`/save-file`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(updatedData),
}).catch((error) => console.error("Error saving file:", error));
}
// Autosave on content change
let timeout;
tableBody.addEventListener("input", function () {
clearTimeout(timeout);
timeout = setTimeout(updateAndSave, autosaveDelay); // Autosave after specified delay of inactivity
});
// Load the file content when the page loads
window.onload = function () {
fetch(`/get-file-content`)
.then((response) => response.json())
.then((data) => {
updateTable(data);
})
.catch((error) => console.error("Error loading file:", error));
};
// Update table with new data
function updateTable(data) {
tableBody.innerHTML = "";
data.forEach((item) => {
const row = tableBody.insertRow();
row.insertCell(0).innerHTML =
'<button class="delete-btn">Delete</button>';
row.insertCell(1).innerText = item.rank;
row.insertCell(2).innerText = item.mowie;
row.insertCell(3).innerText = item.rating;
row.insertCell(4).innerText = item.genre;
});
}
// Handle cell editing
tableBody.addEventListener("dblclick", function (event) {
const cell = event.target.closest("td");
if (cell && cell.cellIndex > 0) {
// Allow editing in all columns except Actions
const originalText = cell.innerText;
const input = document.createElement("input");
input.value = originalText;
input.style.width = "100%";
input.style.boxSizing = "border-box";
input.style.backgroundColor = "var(--input-background)";
input.style.border = "1px solid var(--input-border-color)";
input.style.color = "var(--input-text-color)";
input.style.padding = "8px";
input.style.borderRadius = "4px";
cell.innerHTML = "";
cell.appendChild(input);
input.focus();
input.addEventListener("blur", function () {
const newValue = input.value;
if (newValue !== originalText) {
if (cell.cellIndex === 1) {
// Rank column
const newRank = parseInt(newValue, 10);
if (!isNaN(newRank) && newRank > 0) {
// Update ranks for rows with rank >= newRank
const rows = Array.from(tableBody.rows);
rows.forEach((row) => {
const rankCell = row.cells[1];
const rankValue = parseInt(rankCell.innerText, 10);
if (rankValue >= newRank && rankCell !== cell) {
rankCell.innerText = rankValue + 1;
}
});
// Update the rank of the current cell
cell.innerText = newRank;
// Reorder and update ranks
sortAndReassignRanks(); // Reorder rows and update ranks
} else {
cell.innerText = originalText;
}
} else {
cell.innerText = newValue;
}
updateAndSave(); // Only update and save after changes
} else {
cell.innerText = originalText;
}
});
input.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
input.blur();
}
});
}
});
// Handle row deletion
tableBody.addEventListener("click", function (event) {
if (event.target.classList.contains("delete-btn")) {
const row = event.target.closest("tr");
row.remove();
// Adjust ranks after deletion
updateAndSave(); // Ranks will be sequentially updated in updateAndSave
}
});
</script>
</body>
</html>