diff options
author | Tom Smeding <tom@tomsmeding.com> | 2022-08-22 15:28:10 +0200 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2022-08-22 15:28:10 +0200 |
commit | d1c02019db9a6fb2ab053091c9a4a32dc00b8b50 (patch) | |
tree | dbe9b8846f14d0aa65bb34cdcb0cc8c4d7031d1f /static |
Initial
Diffstat (limited to 'static')
-rw-r--r-- | static/index.css | 91 | ||||
-rw-r--r-- | static/index.html | 13 | ||||
-rw-r--r-- | static/index.js | 196 |
3 files changed, 300 insertions, 0 deletions
diff --git a/static/index.css b/static/index.css new file mode 100644 index 0000000..1d1c542 --- /dev/null +++ b/static/index.css @@ -0,0 +1,91 @@ +body { + font-family: sans-serif; +} + +#list { + font-size: 30px; +} + +.item { + margin-bottom: 4px; +} + +.item.flash { + background-color: #fdd; +} + +.item.negative { + color: #999; +} + +.item.make-new { + margin-top: 7px; +} + +.item .item-buttons { + display: none; + user-select: none; +} +.item:hover .item-buttons { + display: inline; +} + +.item-bullet { + color: #444; + user-select: none; + margin-right: 10px; +} +.item.negative .item-bullet { + color: #aaa; +} + +.item-votes { + display: inline-block; + font-size: 18px; + color: #444; + vertical-align: 3px; + margin-left: 15px; +} + +.item-upvote { + border: 1px #888 solid; + border-radius: 4px; + background-color: #eee; + color: green; + font-weight: bold; + cursor: pointer; + margin-left: 15px; + padding-left: 8px; + padding-right: 8px; +} + +.item-downvote { + font-size: 23px; + color: blue; + cursor: pointer; + margin-left: 15px; + vertical-align: 2px; +} + +.item-delete { + font-weight: bold; + font-family: mononoki; + color: #f00; + font-size: 28px; + margin-left: 11px; + cursor: pointer; +} + +.new-item-bullet { + color: #888; + font-weight: bold; + font-family: mononoki; + margin-left: 1px; + margin-right: 8px; + user-select: none; + vertical-align: 1px; +} + +.new-item-input { + font-size: 26px; +} diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..67ba2f8 --- /dev/null +++ b/static/index.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>List</title> +<script src="/socket.io/socket.io.js"></script> +<script src="/index.js"></script> +<link rel="stylesheet" href="/index.css"> +</head> +<body> + <div id="list"></div> +</body> +</html> diff --git a/static/index.js b/static/index.js new file mode 100644 index 0000000..23d53ea --- /dev/null +++ b/static/index.js @@ -0,0 +1,196 @@ +var socket = null; +var is_initialised = false; +var glist = []; // [(int, string, element)] +var el_list = null; + +function setupSocket() { + socket = io(); + + socket.on("init", function(list) { + // Reload if server restarted + if (!is_initialised) is_initialised = true; + else { location.reload(); return; } + + glist = list; + for (var i = 0; i < glist.length; i++) glist[i].push(null); + initialiseList(); + }); + + socket.on("error", function(err) { + alert("Error: " + err); + }); + + socket.on("alert", function(text) { + alert(text); + }); +} + +// Returns element +function createItemElement(votes, string) { + var el; + + var el_item = document.createElement("div"); + el_item.classList.add("item"); + if (votes < 0) el_item.classList.add("negative"); + + el = document.createElement("span"); + el.classList.add("item-bullet"); + el.appendChild(document.createTextNode("•")); + el_item.appendChild(el); + + el = document.createElement("span"); + el.classList.add("item-label"); + el.appendChild(document.createTextNode(string)); + el_item.appendChild(el); + + el = document.createElement("span"); + el.classList.add("item-votes"); + el.appendChild(document.createTextNode("[" + votes + "]")); + el_item.appendChild(el); + + var buttons = document.createElement("span"); + buttons.classList.add("item-buttons"); + + el = document.createElement("span"); + el.classList.add("item-upvote"); + el.appendChild(document.createTextNode("⇧")); + el.addEventListener("click", function() { + upvoteItem(string, 1); + }); + buttons.appendChild(el); + + el = document.createElement("span"); + el.classList.add("item-downvote"); + el.appendChild(document.createTextNode("↓")); + el.addEventListener("click", function() { + upvoteItem(string, -1); + }); + buttons.appendChild(el); + + el = document.createElement("span"); + el.classList.add("item-delete"); + el.appendChild(document.createTextNode("⨯")); + el.addEventListener("click", function() { + if (votes < 0) deleteItem(string); + else negateItem(string); + }); + buttons.appendChild(el); + + el_item.appendChild(buttons); + + return el_item; +} + +function initialiseList() { + var el_item, el; + el_list.innerHTML = ""; + + for (var i = 0; i < glist.length; i++) { + el_item = createItemElement(glist[i][0], glist[i][1]); + glist[i][2] = el_item; + el_list.appendChild(el_item); + } + + el_item = document.createElement("div"); + el_item.classList.add("item"); + el_item.classList.add("make-new"); + + el = document.createElement("span"); + el.classList.add("new-item-bullet"); + el.appendChild(document.createTextNode("+")); + el_item.appendChild(el); + + el = document.createElement("input"); + el.type = "text"; + el.setAttribute("size", 21); + el.setAttribute("placeholder", "New item..."); + el.classList.add("new-item-input"); + el.addEventListener("keypress", function(ev) { + if (ev.key == "Enter" || ev.keyCode == 10 || ev.keyCode == 13) { + submitNewItem(ev.target.value); + ev.target.value = ""; + } + }); + el_item.appendChild(el); + + el_list.appendChild(el_item); +} + +function submitNewItem(string) { + for (var i = 0; i < glist.length; i++) { + if (glist[i][1] == string) { + var el = glist[i][2]; + el.classList.add("flash"); + setTimeout(function(i) { el.classList.remove("flash"); }, 200); + return; + } + } + + socket.emit("new", string); + + insertItem(0, string); +} + +function upvoteItem(string, incr) { + for (var i = 0; i < glist.length; i++) { + if (glist[i][1] == string) { + glist[i][0] += incr; + socket.emit("set_votes", string, glist[i][0]); + reinsertItem(i); + break; + } + } +} + +function negateItem(string) { + for (var i = 0; i < glist.length; i++) { + if (glist[i][1] == string) { + glist[i][0] = -1; + socket.emit("set_votes", string, -1); + reinsertItem(i); + break; + } + } +} + +function deleteItem(string) { + for (var i = 0; i < glist.length; i++) { + if (glist[i][1] == string) { + socket.emit("delete", string); + glist[i][2].parentElement.removeChild(glist[i][2]); + glist.splice(i, 1); + break; + } + } +} + +function insertItem(votes, string) { + var i; + for (i = 0; i < glist.length; i++) { + if (glist[i][0] > votes) continue; + if (glist[i][0] < votes || glist[i][1] > string) break; + } + var el = createItemElement(votes, string); + if (i == glist.length) { + glist.push([votes, string, el]); + el_list.insertBefore(el, document.querySelector(".item.make-new")); + } else { + var refel = glist[i][2]; + glist.splice(i, 0, [votes, string, el]); + el_list.insertBefore(el, refel); + } +} + +function reinsertItem(index) { + glist[index][2].parentElement.removeChild(glist[index][2]); + var votes = glist[index][0]; + var string = glist[index][1]; + glist.splice(index, 1); + + insertItem(votes, string); +} + +window.addEventListener("load", function() { + el_list = document.getElementById("list"); + setupSocket(); +}); |