Last active
March 6, 2020 16:02
-
-
Save LemoNode/d332002cc3fdfbdd5d4ab5e6b89b266d to your computer and use it in GitHub Desktop.
fart knockers 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<head> | |
<title>Sommar 2020</title> | |
<meta charset="utf-8"> | |
<style> | |
:root { | |
--width: 825px; | |
} | |
body { | |
margin: auto; | |
width: var(--width); | |
font: 12px arial; | |
text-rendering: optimizeSpeed; | |
} | |
#nav { | |
position: sticky; | |
top: 0; | |
background-color: #fff; | |
} | |
#months { | |
display: grid; | |
grid-template-columns: repeat(12, 66px); | |
margin-left: 50px; | |
} | |
.small { | |
font-size: 12px; | |
font-family: consolas; | |
} | |
.medium { | |
font-size: 12px; | |
font-family: consolas; | |
} | |
.large { | |
font-size: 14px; | |
font-family: consolas; | |
} | |
button { | |
border: 1px solid transparent; | |
padding: 5px 5px 5px 5px; | |
border-radius: 3px; | |
outline: none; | |
} | |
#save { | |
background-color: steelblue; | |
color: #fff; | |
} | |
input, select { | |
border: 1px solid #fff; | |
padding: 3px 5px 3px 5px; | |
background: #f0f0f0; | |
outline: none; | |
font-size: 12px; | |
width: auto; | |
margin-right: 5px; | |
} | |
/*svg { | |
border: 1px solid #333; | |
}*/ | |
rect:hover { | |
cursor: pointer; | |
} | |
#add-things { | |
display: grid; | |
grid-template-columns: repeat(2, auto); | |
height: 50px; | |
align-items: center; | |
} | |
</style> | |
</head> | |
<body onload="main();"> | |
<div id="nav"> | |
<br> | |
<h2 style="font-weight: lighter;">Semester önskelista 2020!</h2> | |
<div id="add-things"> | |
<div> | |
<input | |
type="text" | |
placeholder="vgr-id" | |
style="width: 75px;" | |
id="select-id" | |
> | |
<select id="select-team"> | |
<option disabled="true" selected="true">Team</option> | |
<option value="team1">Team 1</option> | |
<option value="team2">Team 2</option> | |
<option value="team3">Team 3</option> | |
</select> | |
<button id="add">Lägg till</button> | |
</div> | |
<div style="margin-left: 450px;"> | |
<p> | |
Status: <b id="status"></b> | |
<button id="save">Spara</button> | |
</p> | |
</div> | |
</div> | |
<div id="months"></div> | |
</div> | |
<div id="calendar"></div> | |
<script> | |
// helpers | |
const h = {}; | |
h.taker = index => { | |
return values => values.constructor.from(index, i => values[i]); | |
} | |
h.filter = (values, test) => { | |
const I = [], n = values.length; | |
for (let i = 0; i < n; ++i) { | |
if (test(values[i], i, values)) { | |
I.push(i); | |
} | |
} | |
return I; | |
} | |
function range (start, stop, step) { | |
const n = arguments.length; | |
start = +start, stop = +stop, step = n < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step; | |
return Uint32Array.from({length: Math.ceil((stop - start) / step)}, (_, i) => start + i * step); | |
} | |
h.ascending = (a, b) => { | |
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; | |
} | |
h.descending = (a, b) => { | |
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; | |
} | |
h.sort = (values, order = h.ascending) => { | |
return range(values.length).sort((i, j) => order(values[i], values[j])); | |
} | |
h.sorti = (values, index, order = h.ascending) => { | |
return index.slice().sort((i, j) => order(values[i], values[j])); | |
} | |
// start of program | |
const dom = { | |
calendar: document.querySelector("#calendar"), | |
body: document.querySelector("body"), | |
months: document.querySelector("#months"), | |
html: document.querySelector("html"), | |
vgrid: document.querySelector("#select-id"), | |
team: document.querySelector("#select-team"), | |
status: document.querySelector("#status"), | |
}; | |
var socket = new WebSocket("ws://" + document.location.host + "/echo"); | |
socket.onopen = function(evt) { | |
dom.status.innerHTML = "Kopplad"; | |
console.log("Yay!"); | |
} | |
socket.onmessage = function(evt) { | |
if (evt.data == "added") { | |
location.reload(); | |
} else if (evt.data == "success") { | |
dom.status.innerHTML = "<b style='color: green;'>Sparat!</b>" | |
window.setTimeout(function() { dom.status.innerHTML = "Kopplad" }, 1500); | |
} | |
console.log(evt.data) | |
} | |
const server = { | |
data: ({{.}}), | |
}; | |
const team_table = { | |
"team1": "steelblue", | |
"team2": "darkorange", | |
"team3": "pink", | |
}; | |
const svg = { | |
width: 825, | |
height: 105, | |
padding: 18, | |
}; | |
const rect = { | |
size: 15, | |
color1: "#fff", | |
color2: "#f0f0f0", | |
prev: null, | |
stroke1: "#ccc", | |
stroke2: "#ddd", | |
single: "#ddd", | |
text1: "#fff", | |
text2: "#666", | |
shift: 10, | |
}; | |
const flags = { | |
month_colored: false, | |
day_colored: false, | |
id: null, | |
}; | |
const user = { | |
day: "crimson", | |
dates: null, | |
clicked: [], | |
}; | |
is_weekend = date => [0, 6].includes(date.getDay()) ? true : false; | |
new_week = (date, week) => date.getDay() == 0 ? week += 1 : week; | |
check_fill = (data, value, month) => { | |
if (data.includes(value)) { | |
return user.day; | |
} else if (month % 2 == 0) { | |
return rect.color1; | |
} else { | |
return rect.color2; | |
} | |
} | |
gen_text_month = dates => { | |
let html = ""; | |
let months = [ | |
"Jan", "Feb", "Mar", "Apr", "Maj", "Jun", | |
"Jul", "Aug", "Sep", "Okt", "Nov", "Dec" | |
]; | |
for (let i = 0; i < months.length; i++) { | |
html += `<text class="large">${months[i]}</text>`; | |
} | |
return html; | |
} | |
gen_rect = (dates, index) => { | |
let html = ""; | |
let week = 0; | |
let user = server.data.dates[index].split(","); | |
for (let i = 0; i < dates.length; i++) { | |
week = new_week(dates[i], week); | |
if (!is_weekend(dates[i])) { | |
let month = +dates[i].toLocaleDateString('se-SE', { month: 'numeric' }); | |
let value = dates[i].toLocaleDateString('se-SE', { | |
year: 'numeric', | |
month: 'numeric', | |
day: 'numeric', | |
}); | |
html += `<rect | |
width="${rect.size}" | |
height="${rect.size}" | |
x="${(week * rect.size) + (month) + svg.padding}" | |
y="${(dates[i].getDay() * rect.size) + (105 * index)}" | |
fill="${check_fill(user, value, month)}" | |
stroke="${rect.stroke1}" | |
value="${value}" | |
></rect>`; | |
} | |
} | |
return html; | |
} | |
gen_text_days = (dates, index) => { | |
let html = ""; | |
let week = 0; | |
for (let i = 0; i < dates.length; i++) { | |
week = new_week(dates[i], week); | |
if (!is_weekend(dates[i])) { | |
let day = +dates[i].toLocaleDateString('se-SE', { day: 'numeric' }); | |
let month = +dates[i].toLocaleDateString('se-SE', { month: 'numeric' }); | |
let value = dates[i].toLocaleDateString('se-SE', { | |
year: 'numeric', | |
month: 'numeric', | |
day: 'numeric', | |
}); | |
html += `<text | |
x="${(week * rect.size) + (month ) + svg.padding}" | |
y="${(dates[i].getDay() * rect.size) + (105 * index)}" | |
dx="1" | |
dy="${rect.size - 3}" | |
class="small day" | |
fill="${rect.text1}" | |
pointer-events="none" | |
value="${value}" | |
>${day <= 9 ? "0" + day : day}</text>` | |
} | |
} | |
return html; | |
} | |
gen_text_weeek = (dates, index) => { | |
let html = ""; | |
let team = server.data.teams[index]; | |
let weeks = ["Må", "Ti", "On", "To", "Fr"]; | |
for (let i = 0; i < weeks.length; i++) { | |
html += `<text | |
x="0" | |
y="${(i + 1) * rect.size + (105 * index)}" | |
dy="${rect.size - 3}" | |
class="small" | |
fill="${team_table[team]}" | |
>${weeks[i]}</text>`; | |
} | |
return html; | |
} | |
gen_text_vgrid = (id, index) => { | |
let html = `<text | |
x="0" | |
y="${(rect.size * 5) + svg.padding + rect.size + (105 * index)}" | |
class="medium" | |
fill="#111" | |
font-weight="bold" | |
>ID: ${id}</text>`; | |
return html; | |
} | |
gen_calendar = dates => { | |
let ids = server.data.vgrid; | |
let html = ""; | |
html += `<svg | |
width="${svg.width}" | |
height="${svg.height * ids.length + svg.padding}" | |
>`; | |
for (var i = 0; i < ids.length; i++) { | |
html += `<g id="${ids[i]}">`; | |
html += gen_rect(dates, i); | |
html += gen_text_days(dates, i); | |
html += gen_text_weeek(dates, i); | |
html += gen_text_vgrid(ids[i], i); | |
html += "</g>"; | |
} | |
html += "</svg>"; | |
return html; | |
} | |
gen_dates = year => { | |
let start = new Date(year, 0, 1); | |
let end = new Date(year + 1, 0, 0); | |
let arr = []; | |
for (let date = start; date <= end; date.setDate(date.getDate() + 1)) { | |
arr.push(new Date(date)); | |
} | |
return arr; | |
} | |
reset_color = id => { | |
let node = document.querySelector(`#${id}`); | |
let text = node.querySelectorAll(".day"); | |
for (let i = 0; i < text.length; i++) { | |
text[i].attributes.fill.value = rect.text1; | |
} | |
return text; | |
} | |
color_text = (e, id) => { | |
let month = e.target.attributes.value.value.split("-")[1]; | |
let text = reset_color(id); | |
for (let i = 0; i < text.length; i++) { | |
if (text[i].attributes.value == undefined) { | |
break; | |
} | |
let item_value = text[i].attributes.value.value.split("-")[1]; | |
if (item_value == month) { | |
text[i].attributes.fill.value = rect.text2; | |
flags.month_colored = true; | |
flags.id = id; | |
} | |
} | |
} | |
mouse_move = e => { | |
let id = e.target.parentNode.id; | |
if (flags.month_colored && e.target.tagName != "rect") { | |
flags.month_colored = false; | |
reset_color(flags.id); | |
} | |
if (e.target.tagName == "rect") { | |
color_text(e, id); | |
} else if (rect.prev != null) { | |
rect.prev.target.attributes.fill.value = rect.color1; | |
rect.prev = null; | |
} | |
} | |
clicked_rect = e => { | |
if (e.target.tagName == "rect") { | |
let id = e.target.parentNode.id; | |
// coloring | |
if (e.target.attributes.fill.value == user.day) { | |
if (e.target.attributes.value.value.split("-")[1] % 2 == 0) { | |
e.target.attributes.fill.value = rect.color1; | |
} else { | |
e.target.attributes.fill.value = rect.color2; | |
} | |
} else { | |
e.target.attributes.fill.value = user.day; | |
} | |
rect.prev = null; | |
// adding | |
if (!user.clicked.includes(id)) { | |
user.clicked.push(id); | |
} | |
var index = user.dates[id].indexOf(e.target.attributes.value.value); | |
if (index > -1) { | |
user.dates[id].splice(index, 1); | |
} else { | |
user.dates[id].push(e.target.attributes.value.value); | |
} | |
} | |
} | |
clicked_save = e => { | |
if (e.target.id == "save" && user.clicked.length != 0) { | |
let result = "save||"; | |
let ids = Object.keys(user.dates) | |
let counter = 0; | |
for (let i = 0; i < ids.length; i++) { | |
if (user.clicked.includes(ids[i])) { | |
var index = user.dates[ids[i]].indexOf(""); | |
if (index > -1) { | |
user.dates[ids[i]].splice(index, 1); | |
} | |
if (counter > 0) { | |
result += " " + ids[i] + ":" + user.dates[ids[i]].join(); | |
} else { | |
result += ids[i] + ":" + user.dates[ids[i]].join(); | |
} | |
counter++; | |
} | |
} | |
user.clicked = []; | |
socket.send(result); | |
} | |
} | |
clicked_add = e => { | |
if (e.target.id == "add") { | |
if (dom.vgrid.value == "") { | |
alert("Måste skriva vgrid"); | |
} | |
if (server.data["vgrid"].includes(dom.vgrid.value)) { | |
alert("Vgrid finns redan i listan!"); | |
} else { | |
let id = dom.vgrid.value; | |
let teams = dom.team.querySelectorAll("option"); | |
for (let i = 0; i < teams.length; i++) { | |
if (teams[i].selected == true && teams[i].value == "Team") { | |
alert("Måste välja team"); | |
break; | |
} else if (teams[i].selected == true) { | |
let result = "add||"; | |
result += id + ":" + teams[i].value; | |
socket.send(result); | |
} | |
} | |
} | |
} | |
} | |
mouse_click = e => { | |
clicked_rect(e); | |
clicked_save(e); | |
clicked_add(e); | |
} | |
get_ids = () => { | |
var objs = {}; | |
for (let i = 0; i < server.data.vgrid.length; i++) { | |
objs[server.data.vgrid[i]] = []; | |
} | |
for (let i = 0; i < server.data.dates.length; i++) { | |
var ammount = server.data.dates[i].split(","); | |
for (let j = 0; j < ammount.length; j++) { | |
objs[server.data.vgrid[i]].push(ammount[j]); | |
} | |
} | |
return objs; | |
} | |
team_to_nr = teams => { | |
let arr = []; | |
for (let i = 0; i < teams.length; i++) { | |
if (teams[i] == "team1") arr.push(1); | |
if (teams[i] == "team2") arr.push(2); | |
if (teams[i] == "team3") arr.push(3); | |
} | |
return arr; | |
} | |
nr_to_team = teams => { | |
let arr = []; | |
for (let i = 0; i < teams.length; i++) { | |
if (teams[i] == 1) arr.push("team1"); | |
if (teams[i] == 2) arr.push("team2"); | |
if (teams[i] == 3) arr.push("team3"); | |
} | |
return arr; | |
} | |
cleanup_data = () => { | |
let team_nr = team_to_nr(server.data["teams"]) | |
let collection = [server.data["vgrid"], team_nr, server.data["dates"]] | |
let new_arr = collection.map(h.taker(h.sort(team_nr, h.ascending))) | |
let new_team = nr_to_team(new_arr[1]); | |
new_arr[1] = new_team; | |
server.data["vgrid"] = new_arr[0]; | |
server.data["teams"] = new_arr[1]; | |
server.data["dates"] = new_arr[2]; | |
} | |
main = () => { | |
cleanup_data(); | |
let dates = gen_dates(new Date().getFullYear()); | |
user.dates = get_ids(); | |
dom.calendar.innerHTML = gen_calendar(dates); | |
dom.months.innerHTML = gen_text_month(dates); | |
dom.html.onmousemove = e => mouse_move(e); | |
dom.body.onclick = e => mouse_click(e); | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment