all repos — honk @ aaa5c334a99e501f801ad5f0364678fd81707988

my fork of honk

views/honkpage.js (view raw)

  1var csrftoken = ""
  2var honksforpage = { }
  3var curpagestate = { name: "", arg : "" }
  4var tophid = { }
  5var servermsgs = { }
  6
  7function encode(hash) {
  8	var s = []
  9	for (var key in hash) {
 10		var val = hash[key]
 11		s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val))
 12	}
 13	return s.join("&")
 14}
 15function post(url, data) {
 16	var x = new XMLHttpRequest()
 17	x.open("POST", url)
 18	x.timeout = 30 * 1000
 19	x.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
 20	x.send(data)
 21}
 22function get(url, whendone, errfunction) {
 23	var x = new XMLHttpRequest()
 24	x.open("GET", url)
 25	x.timeout = 15 * 1000
 26	x.responseType = "json"
 27	x.onload = function() { whendone(x) }
 28	if (errfunction) {
 29		x.ontimeout = function(e) { errfunction(" timed out") }
 30		x.onerror = function(e) { errfunction(" error") }
 31	}
 32	x.send()
 33}
 34function bonk(el, xid) {
 35	el.innerHTML = "bonked"
 36	el.disabled = true
 37	post("/bonk", encode({"js": "2", "CSRF": csrftoken, "xid": xid}))
 38	return false
 39}
 40function unbonk(el, xid) {
 41	el.innerHTML = "unbonked"
 42	el.disabled = true
 43	post("/zonkit", encode({"CSRF": csrftoken, "wherefore": "unbonk", "what": xid}))
 44}
 45function muteit(el, convoy) {
 46	el.innerHTML = "muted"
 47	el.disabled = true
 48	post("/zonkit", encode({"CSRF": csrftoken, "wherefore": "zonvoy", "what": convoy}))
 49	var els = document.querySelectorAll('article.honk')
 50	for (var i = 0; i < els.length; i++) {
 51		var e = els[i]
 52		if (e.getAttribute("data-convoy") == convoy) {
 53			e.remove()
 54		}
 55	}
 56}
 57function zonkit(el, xid) {
 58	el.innerHTML = "zonked"
 59	el.disabled = true
 60	post("/zonkit", encode({"CSRF": csrftoken, "wherefore": "zonk", "what": xid}))
 61	var p = el
 62	while (p && p.tagName != "ARTICLE") {
 63		p = p.parentElement
 64	}
 65	if (p) {
 66		p.remove()
 67	}
 68}
 69function flogit(el, how, xid) {
 70	var s = how
 71	if (s[s.length-1] != "e") { s += "e" }
 72	s += "d"
 73	if (s == "untaged") s = "untagged"
 74	if (s == "reacted") s = "badonked"
 75	el.innerHTML = s
 76	el.disabled = true
 77	post("/zonkit", encode({"CSRF": csrftoken, "wherefore": how, "what": xid}))
 78}
 79
 80var lehonkform = document.getElementById("honkform")
 81var lehonkbutton = document.getElementById("honkingtime")
 82
 83function oldestnewest(btn) {
 84	var els = document.getElementsByClassName("glow")
 85	if (els.length) {
 86		els[els.length-1].scrollIntoView({ behavior: "smooth" })
 87	}
 88}
 89function removeglow() {
 90	var els = document.getElementsByClassName("glow")
 91	while (els.length) {
 92		els[0].classList.remove("glow")
 93	}
 94}
 95
 96function fillinhonks(xhr, glowit) {
 97	var resp = xhr.response
 98	var stash = curpagestate.name + ":" + curpagestate.arg
 99	tophid[stash] = resp.Tophid
100	var doc = document.createElement( 'div' );
101	doc.innerHTML = resp.Srvmsg
102	var srvmsg = doc
103	doc = document.createElement( 'div' );
104	doc.innerHTML = resp.Honks
105	var honks = doc.children
106
107	var mecount = document.getElementById("mecount")
108	if (resp.MeCount) {
109		mecount.innerHTML = resp.MeCount
110		mecount.style.width = "18px"
111	} else {
112		mecount.innerHTML = ""
113	}
114	var chatcount = document.getElementById("chatcount")
115	if (resp.ChatCount) {
116		chatcount.innerHTML = resp.ChatCount
117	} else {
118		chatcount.innerHTML = ""
119	}
120
121	var srvel = document.getElementById("srvmsg")
122	while (srvel.children[0]) {
123		srvel.children[0].remove()
124	}
125	srvel.prepend(srvmsg)
126
127	var frontload = true
128	if (curpagestate.name == "convoy") {
129		frontload = false
130	}
131
132	var honksonpage = document.getElementById("honksonpage")
133	var holder = honksonpage.children[0]
134	var lenhonks = honks.length
135	for (var i = honks.length; i > 0; i--) {
136		var h = honks[frontload ? i-1 : 0]
137		if (glowit)
138			h.classList.add("glow")
139		if (frontload) {
140			holder.prepend(h)
141		} else {
142			holder.append(h)
143		}
144	}
145	relinklinks()
146	return lenhonks
147}
148function hydrargs() {
149	var name = curpagestate.name
150	var arg = curpagestate.arg
151	var args = { "page" : name }
152	if (name == "convoy") {
153		args["c"] = arg
154	} else if (name == "combo") {
155		args["c"] = arg
156	} else if (name == "honker") {
157		args["xid"] = arg
158	} else if (name == "user") {
159		args["uname"] = arg
160	}
161	return args
162}
163function refreshupdate(msg) {
164	var el = document.querySelector("#refreshbox p span")
165	if (el) {
166		el.innerHTML = msg
167	}
168}
169function refreshhonks(btn) {
170	removeglow()
171	btn.innerHTML = "refreshing"
172	btn.disabled = true
173	var args = hydrargs()
174	var stash = curpagestate.name + ":" + curpagestate.arg
175	args["tophid"] = tophid[stash]
176	get("/hydra?" + encode(args), function(xhr) {
177		btn.innerHTML = "refresh"
178		btn.disabled = false
179		if (xhr.status == 200) {
180			var lenhonks = fillinhonks(xhr, true)
181			refreshupdate(" " + lenhonks + " new")
182		} else {
183			refreshupdate(" status: " + xhr.status)
184		}
185	}, function(err) {
186		btn.innerHTML = "refresh"
187		btn.disabled = false
188		refreshupdate(err)
189	})
190}
191function statechanger(evt) {
192	var data = evt.state
193	if (!data) {
194		return
195	}
196	switchtopage(data.name, data.arg)
197}
198function switchtopage(name, arg) {
199	var stash = curpagestate.name + ":" + curpagestate.arg
200	var honksonpage = document.getElementById("honksonpage")
201	var holder = honksonpage.children[0]
202	holder.remove()
203	var srvel = document.getElementById("srvmsg")
204	var msg = srvel.children[0]
205	if (msg) {
206		msg.remove()
207		servermsgs[stash] = msg
208	}
209	showelement("refreshbox")
210
211	honksforpage[stash] = holder
212
213	curpagestate.name = name
214	curpagestate.arg = arg
215	// get the holder for the target page
216	stash = name + ":" + arg
217	holder = honksforpage[stash]
218	if (holder) {
219		honksonpage.prepend(holder)
220		msg = servermsgs[stash]
221		if (msg) {
222			srvel.prepend(msg)
223		}
224	} else {
225		// or create one and fill it
226		honksonpage.prepend(document.createElement("div"))
227		var args = hydrargs()
228		get("/hydra?" + encode(args), function(xhr) {
229			if (xhr.status == 200) {
230				fillinhonks(xhr, false)
231			} else {
232				refreshupdate(" status: " + xhr.status)
233			}
234		}, function(err) {
235			refreshupdate(err)
236		})
237	}
238	refreshupdate("")
239}
240function newpagestate(name, arg) {
241	return { "name": name, "arg": arg }
242}
243function pageswitcher(name, arg) {
244	return function(evt) {
245		var topmenu = document.getElementById("topmenu")
246		topmenu.open = false
247		if (name == curpagestate.name && arg == curpagestate.arg) {
248			return false
249		}
250		switchtopage(name, arg)
251		var url = evt.srcElement.href
252		if (!url) {
253			url = evt.srcElement.parentElement.href
254		}
255		history.pushState(newpagestate(name, arg), "some title", url)
256		window.scrollTo(0, 0)
257		return false
258	}
259}
260function relinklinks() {
261	var els = document.getElementsByClassName("convoylink")
262	while (els.length) {
263    var s = (new URL(els[0].href)).search
264    var c = new URLSearchParams(s).get('c')
265		els[0].onclick = pageswitcher("convoy", c)
266		els[0].classList.remove("convoylink")
267	}
268	els = document.getElementsByClassName("combolink")
269	while (els.length) {
270		els[0].onclick = pageswitcher("combo", els[0].text)
271		els[0].classList.remove("combolink")
272	}
273	els = document.getElementsByClassName("honkerlink")
274	while (els.length) {
275		var el = els[0]
276		var xid = el.getAttribute("data-xid")
277		el.onclick = pageswitcher("honker", xid)
278		el.classList.remove("honkerlink")
279	}
280	els = document.getElementsByClassName("donklink")
281	while (els.length) {
282		let el = els[0]
283		el.onclick = function() {
284			el.classList.remove("donk")
285			el.onclick = null
286			return false
287		}
288		el.classList.remove("donklink")
289	}
290
291	els = document.querySelectorAll("#honksonpage article button")
292	els.forEach(function(el) {
293		var honk = el.closest("article")
294		var convoy = honk.dataset.convoy
295		var hname = honk.dataset.hname
296		var xid = honk.dataset.xid
297		var id = Number(honk.dataset.id)
298
299		if (!(id > 0)) {
300			console.error("could not determine honk id")
301			return
302		}
303
304		if (el.classList.contains("unbonk")) {
305			el.onclick = function() {
306				unbonk(el, xid);
307			}
308		} else if (el.classList.contains("bonk")) {
309			el.onclick = function() {
310				bonk(el, xid)
311			}
312		} else if (el.classList.contains("honkback")) {
313			el.onclick = function() {
314				return showhonkform(el, xid, hname)
315			}
316		} else if (el.classList.contains("mute")) {
317			el.onclick = function() {
318				muteit(el, convoy);
319			}
320		} else if (el.classList.contains("evenmore")) {
321			var more = document.querySelector("#evenmore"+id);
322			el.onclick = function() {
323				more.classList.toggle("hide");
324			}
325		} else if (el.classList.contains("zonk")) {
326			el.onclick = function() {
327				zonkit(el, xid);
328			}
329		} else if (el.classList.contains("flogit-deack")) {
330			el.onclick = function() {
331				flogit(el, "deack", xid);
332			}
333		} else if (el.classList.contains("flogit-ack")) {
334			el.onclick = function() {
335				flogit(el, "ack", xid);
336			}
337		} else if (el.classList.contains("flogit-unsave")) {
338			el.onclick = function() {
339				flogit(el, "unsave", xid);
340			}
341		} else if (el.classList.contains("flogit-save")) {
342			el.onclick = function() {
343				flogit(el, "save", xid);
344			}
345		} else if (el.classList.contains("flogit-untag")) {
346			el.onclick = function() {
347				flogit(el, "untag", xid);
348			}
349		} else if (el.classList.contains("flogit-react")) {
350			el.onclick = function() {
351				flogit(el, "react", xid);
352			}
353		}
354	})
355}
356function showhonkform(elem, rid, hname) {
357	var form = lehonkform
358	form.style = "display: block"
359	form.reset()
360	if (elem) {
361		form.remove()
362		elem.parentElement.parentElement.parentElement.insertAdjacentElement('beforebegin', form)
363	} else {
364		hideelement(lehonkbutton)
365		elem = document.getElementById("honkformhost")
366		elem.insertAdjacentElement('afterend', form)
367	}
368	var donker = document.getElementById("donker")
369	donker.children[1].textContent = ""
370	var ridinput = document.getElementById("ridinput")
371	var honknoise = document.getElementById("honknoise")
372	if (rid) {
373		ridinput.value = rid
374		if (hname) {
375			honknoise.value = hname + " "
376		} else {
377			honknoise.value = ""
378		}
379	} else {
380		ridinput.value = ""
381		honknoise.value = ""
382	}
383	var updateinput = document.getElementById("updatexidinput")
384	updateinput.value = ""
385	var savedfile = document.getElementById("saveddonkxid")
386	savedfile.value = ""
387	honknoise.focus()
388	return false
389}
390function cancelhonking() {
391	hideelement(lehonkform)
392	showelement(lehonkbutton)
393}
394function showelement(el) {
395	if (typeof(el) == "string")
396		el = document.getElementById(el)
397	if (!el) return
398	el.style.display = "block"
399}
400function hideelement(el) {
401	if (typeof(el) == "string")
402		el = document.getElementById(el)
403	if (!el) return
404	el.style.display = "none"
405}
406function updatedonker(ev) {
407	var el = ev.target.parentElement
408	el.children[1].textContent = el.children[0].value.slice(-20)
409	el = el.nextSibling
410	el.value = ""
411	el = el.parentElement.nextSibling
412	el.style.display = ""
413}
414var checkinprec = 100.0
415var gpsoptions = {
416	enableHighAccuracy: false,
417	timeout: 1000,
418	maximumAge: 0
419};
420function fillcheckin() {
421	if (navigator.geolocation) {
422		navigator.geolocation.getCurrentPosition(function(pos) {
423			showelement("placedescriptor")
424			var el = document.getElementById("placelatinput")
425			el.value = Math.round(pos.coords.latitude * checkinprec) / checkinprec
426			el = document.getElementById("placelonginput")
427			el.value = Math.round(pos.coords.longitude * checkinprec) / checkinprec
428			checkinprec = 10000.0
429			gpsoptions.enableHighAccuracy = true
430			gpsoptions.timeout = 2000
431		}, function(err) {
432			showelement("placedescriptor")
433			var el = document.getElementById("placenameinput")
434			el.value = err.message
435		}, gpsoptions)
436	}
437}
438
439function scrollnexthonk() {
440	var honks = document.getElementsByClassName("honk");
441	for (var i = 0; i < honks.length; i++) {
442		var h = honks[i];
443		var b = h.getBoundingClientRect();
444		if (b.top > 1.0) {
445			h.scrollIntoView()
446			var a = h.querySelector(".actions summary")
447			if (a) a.focus({ preventScroll: true })
448			break
449		}
450	}
451}
452
453function scrollprevioushonk() {
454	var honks = document.getElementsByClassName("honk");
455	for (var i = 1; i < honks.length; i++) {
456		var b = honks[i].getBoundingClientRect();
457		if (b.top > -1.0) {
458			honks[i-1].scrollIntoView()
459			var a = honks[i-1].querySelector(".actions summary")
460			if (a) a.focus({ preventScroll: true })
461			break
462		}
463	}
464}
465
466function hotkey(e) {
467	if (e.ctrlKey || e.altKey)
468		return
469	if (e.code == "Escape") {
470		var menu = document.getElementById("topmenu")
471		menu.open = false
472		return
473	}
474	if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
475		return
476
477	switch (e.code) {
478	case "KeyR":
479		refreshhonks(document.getElementById("honkrefresher"));
480		break;
481	case "KeyS":
482		oldestnewest(document.getElementById("newerscroller"));
483		break;
484	case "KeyJ":
485		scrollnexthonk();
486		break;
487	case "KeyK":
488		scrollprevioushonk();
489		break;
490	case "KeyM":
491		var menu = document.getElementById("topmenu")
492		if (!menu.open) {
493			menu.open = true
494			menu.querySelector("a").focus()
495		} else {
496			menu.open = false
497		}
498		break
499	case "Slash":
500		document.getElementById("topmenu").open = true
501		document.getElementById("searchbox").focus()
502		e.preventDefault()
503		break
504	}
505}
506
507document.addEventListener("keydown", hotkey)
508
509function addemu(elem) {
510	const data = elem.alt
511	const box = document.getElementById("honknoise");
512	box.value += data;
513}
514function loademus() {
515	var div = document.getElementById("emupicker")
516	var request = new XMLHttpRequest()
517	request.open('GET', '/emus')
518	request.onload = function() {
519		div.innerHTML = request.responseText
520		div.querySelectorAll(".emu").forEach(function(el) {
521			el.onclick = function() {
522				addemu(el)
523			}
524		})
525	}
526	if (div.style.display === "none") {
527		div.style.display = "block";
528	} else {
529		div.style.display = "none";
530	}
531	request.send()
532}
533
534// init
535(function() {
536	var me = document.currentScript;
537	csrftoken = me.dataset.csrf
538	curpagestate.name = me.dataset.pagename
539	curpagestate.arg = me.dataset.pagearg
540	tophid[curpagestate.name + ":" + curpagestate.arg] = me.dataset.tophid
541	servermsgs[curpagestate.name + ":" + curpagestate.arg] = me.dataset.srvmsg
542
543	var el = document.getElementById("homelink")
544	el.onclick = pageswitcher("home", "")
545	el = document.getElementById("atmelink")
546	el.onclick = pageswitcher("atme", "")
547	el = document.getElementById("firstlink")
548	el.onclick = pageswitcher("first", "")
549	el = document.getElementById("savedlink")
550	el.onclick = pageswitcher("saved", "")
551	el = document.getElementById("longagolink")
552	el.onclick = pageswitcher("longago", "")
553
554	var totop = document.querySelector(".nophone")
555	if (totop) {
556		totop.onclick = function() {
557			window.scrollTo(0,0)
558		}
559	}
560
561	var refreshbox = document.getElementById("refreshbox")
562	if (refreshbox) {
563		refreshbox.querySelectorAll("button").forEach(function(el) {
564			if (el.classList.contains("refresh")) {
565				el.onclick = function() {
566					refreshhonks(el)
567				}
568			} else if (el.classList.contains("scrolldown")) {
569				el.onclick = function() {
570					oldestnewest(el)
571				}
572			}
573		})
574
575		if (me.dataset.srvmsg == "one honk maybe more") {
576			hideelement(refreshbox)
577		}
578	}
579
580	var td = document.getElementById("timedescriptor")
581	document.getElementById("addtimebutton").onclick = function() {
582		td.classList.toggle("hide")
583	}
584	document.getElementById("honkingtime").onclick = function() {
585		return showhonkform()
586	}
587	document.getElementById("checkinbutton").onclick = fillcheckin
588	document.getElementById("emuload").onclick = loademus
589	document.querySelector("#donker input").onchange = updatedonker
590	document.querySelector("button[name=cancel]").onclick = cancelhonking
591
592	relinklinks()
593	window.onpopstate = statechanger
594	history.replaceState(curpagestate, "some title", "")
595
596	hideelement("donkdescriptor")
597})();