diff options
Diffstat (limited to 'ikiwiki')
-rw-r--r-- | ikiwiki/ikiwiki.js | 54 | ||||
-rw-r--r-- | ikiwiki/relativedate.js | 75 | ||||
-rw-r--r-- | ikiwiki/toggle.js | 29 |
3 files changed, 158 insertions, 0 deletions
diff --git a/ikiwiki/ikiwiki.js b/ikiwiki/ikiwiki.js new file mode 100644 index 0000000..aebc5cf --- /dev/null +++ b/ikiwiki/ikiwiki.js @@ -0,0 +1,54 @@ +// ikiwiki's javascript utility function library + +var hooks; + +// Run onload as soon as the DOM is ready, if possible. +// gecko, opera 9 +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", run_hooks_onload, false); +} +// other browsers +window.onload = run_hooks_onload; + +var onload_done = 0; + +function run_hooks_onload() { + // avoid firing twice + if (onload_done) + return; + onload_done = true; + + run_hooks("onload"); +} + +function run_hooks(name) { + if (typeof(hooks) != "undefined") { + for (var i = 0; i < hooks.length; i++) { + if (hooks[i].name == name) { + hooks[i].call(); + } + } + } +} + +function hook(name, call) { + if (typeof(hooks) == "undefined") + hooks = new Array; + hooks.push({name: name, call: call}); +} + +function getElementsByClass(cls, node, tag) { + if (document.getElementsByClass) + return document.getElementsByClass(cls, node, tag); + if (! node) node = document; + if (! tag) tag = '*'; + var ret = new Array(); + var pattern = new RegExp("(^|\\s)"+cls+"(\\s|$)"); + var els = node.getElementsByTagName(tag); + for (i = 0; i < els.length; i++) { + if ( pattern.test(els[i].className) ) { + ret.push(els[i]); + } + } + return ret; +} diff --git a/ikiwiki/relativedate.js b/ikiwiki/relativedate.js new file mode 100644 index 0000000..2a270d6 --- /dev/null +++ b/ikiwiki/relativedate.js @@ -0,0 +1,75 @@ +// Causes html elements in the 'relativedate' class to be displayed +// as relative dates. The date is parsed from the title attribute, or from +// the element content. + +var dateElements; + +hook("onload", getDates); + +function getDates() { + dateElements = getElementsByClass('relativedate'); + for (var i = 0; i < dateElements.length; i++) { + var elt = dateElements[i]; + var title = elt.attributes.title; + var d = new Date(title ? title.value : elt.innerHTML); + if (! isNaN(d)) { + dateElements[i].date=d; + elt.title=elt.innerHTML; + } + } + + showDates(); +} + +function showDates() { + for (var i = 0; i < dateElements.length; i++) { + var elt = dateElements[i]; + var d = elt.date; + if (! isNaN(d)) { + elt.innerHTML=relativeDate(d); + } + } + setTimeout(showDates,30000); // keep updating every 30s +} + +var timeUnits = [ + { unit: 'year', seconds: 60 * 60 * 24 * 364 }, + { unit: 'month', seconds: 60 * 60 * 24 * 30 }, + { unit: 'day', seconds: 60 * 60 * 24 }, + { unit: 'hour', seconds: 60 * 60 }, + { unit: 'minute', seconds: 60 }, +]; + +function relativeDate(date) { + var now = new Date(); + var offset = date.getTime() - now.getTime(); + var seconds = Math.round(Math.abs(offset) / 1000); + + // hack to avoid reading just in the future if there is a minor + // amount of clock slip + if (offset >= 0 && seconds < 30 * 60 * 60) { + return "just now"; + } + + var ret = ""; + var shown = 0; + for (i = 0; i < timeUnits.length; i++) { + if (seconds >= timeUnits[i].seconds) { + var num = Math.floor(seconds / timeUnits[i].seconds); + seconds -= num * timeUnits[i].seconds; + if (ret) + ret += "and "; + ret += num + " " + timeUnits[i].unit + (num > 1 ? "s" : "") + " "; + + if (++shown == 2) + break; + } + else if (shown) + break; + } + + if (! ret) + ret = "less than a minute " + + return ret + (offset < 0 ? "ago" : "from now"); +} diff --git a/ikiwiki/toggle.js b/ikiwiki/toggle.js new file mode 100644 index 0000000..d190b73 --- /dev/null +++ b/ikiwiki/toggle.js @@ -0,0 +1,29 @@ +// Uses CSS to hide toggleables, to avoid any flashing on page load. The +// CSS is only emitted after it tests that it's going to be able +// to show the toggleables. +if (document.getElementById && document.getElementsByTagName && document.createTextNode) { + document.write('<style type="text/css">div.toggleable { display: none; }</style>'); + hook("onload", inittoggle); +} + +function inittoggle() { + var as = getElementsByClass('toggle'); + for (var i = 0; i < as.length; i++) { + var id = as[i].href.match(/#(\w.+)/)[1]; + if (document.getElementById(id).className == "toggleable") + document.getElementById(id).style.display="none"; + as[i].onclick = function() { + toggle(this); + return false; + } + } +} + +function toggle(s) { + var id = s.href.match(/#(\w.+)/)[1]; + style = document.getElementById(id).style; + if (style.display == "none") + style.display = "block"; + else + style.display = "none"; +} |