all repos — honk @ 2a20b1671d9f032ffffb1023dd104e2e7e4f31ec

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