posts.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. function checkLinkHref(elms) {
  2. //console.log("checkLinkHref");
  3. for (let a of elms) {
  4. //console.log(a.href);
  5. fetch(a.href)
  6. .then(function(response) {
  7. //console.log("checkLinkHref II");
  8. if (response.ok)
  9. return;
  10. //console.log("checkLinkHref III");
  11. a.classList.remove("enabled");
  12. a.classList.add("disabled");
  13. })
  14. .catch(function(err) {
  15. //console.log("checkLinkHref");
  16. console.log(a.href);
  17. console.log(err);
  18. }) ;
  19. }
  20. }
  21. function toggle() {
  22. switch(document.cookie) {
  23. case 'dark':
  24. document.cookie = 'light';
  25. break;
  26. case 'light':
  27. document.cookie = '';
  28. break;
  29. default:
  30. document.cookie = 'dark';
  31. break;
  32. }
  33. console.log("uhu: "+document.cookie);
  34. const lst = document.documentElement.classList;
  35. lst.remove('dark');
  36. lst.remove('light');
  37. lst.add(document.cookie);
  38. }
  39. // list tags with font-size in relation to frequency
  40. // https://github.com/sebsauvage/Shaarli/blob/master/index.php#L1254
  41. function computeTagFontsize(tag0) {
  42. if (!tag0)
  43. return;
  44. const fontMin = 8;
  45. const fontMax = 32;
  46. var countMaxLog = Math.log(1);
  47. const tags = tag0.getElementsByTagName('a');
  48. const counts = new Array(tags.length);
  49. const log = {};
  50. for (var i = tags.length - 1; i >= 0; i--) {
  51. const lbl = tags[i].getElementsByClassName('label')[0].textContent;
  52. if ('2018-01-15T12:52' == lbl) {
  53. counts[i] = 1;
  54. continue;
  55. }
  56. const elm = tags[i].getElementsByClassName('count')[0];
  57. const txt = elm.textContent;
  58. var v = log[txt];
  59. if (!v)
  60. log[txt] = v = Math.log(parseInt(txt, 10));
  61. counts[i] = v;
  62. countMaxLog = Math.max(countMaxLog, counts[i]);
  63. }
  64. log.length = 0;
  65. const factor = 1.0 / countMaxLog * (fontMax - fontMin);
  66. requestAnimationFrame(function() { // http://wilsonpage.co.uk/preventing-layout-thrashing/
  67. for (var i = tags.length - 1; i >= 0; i--) {
  68. const k = counts[i];
  69. var v = log[k];
  70. if (!v)
  71. // https://stackoverflow.com/a/3717340
  72. log[k] = v = Math.ceil(k * factor + fontMin) + 'pt';
  73. tags[i].style.fontSize = v;
  74. }
  75. });
  76. }
  77. // https://varvy.com/pagespeed/defer-images.html
  78. function loadDeferredImages(imgsDefer) {
  79. // console.log('loadDeferredImages: ' + imgsDefer.length);
  80. for (var i = imgsDefer.length - 1; i >= 0 ; i--) {
  81. const v = imgsDefer[i].getAttribute('data-src');
  82. if (!v)
  83. continue;
  84. imgsDefer[i].setAttribute('src', v);
  85. }
  86. }
  87. // make http and geo URIs (RFC 5870) clickable + microformat
  88. function clickableTextLinks(elmsRendered) {
  89. // console.log('make http and geo URIs (RFC 5870) clickable + microformat');
  90. for (var i = elmsRendered.length - 1; i >= 0 ; i--) {
  91. const elm = elmsRendered[i];
  92. elm.innerHTML = elm.innerHTML
  93. .replace(/(https?:\/\/([^ \t\r\n"'<>]+[^ ?\t\r\n"'<>.,;:()]))/gi, '<a rel="noreferrer" class="http" href="$1">$2</a>')
  94. // https://alanstorm.com/url_regex_explained/ \b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))
  95. // .replace(/\b(([\w-]+:\/\/?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/)))/gi, '<a rel="noreferrer" class="http" href="$1">$1</a>')
  96. .replace(/(https?:\/\/(www\.)?(youtu\.be|youtube\.com)\/[^'" ]+)/gi, 'https://mro.name/$1')
  97. .replace(/geo:(-?\d+.\d+),(-?\d+.\d+)(\?z=(\d+))?/gi, '<a class="geo" href="https://opentopomap.org/#marker=12/$1/$2" title="zoom=$4">geo:<span class="latitude">$1</span>,<span class="longitude">$2</span>$3</a>')
  98. .replace(/(#RFC(\d+)(#\S*[0-9a-z])?)/gi, '<a class="rfc" href="https://tools.ietf.org/html/rfc$2$3" title="RFC $2">$1</a>')
  99. .replace(/(urn:ietf:rfc:(\d+)(#\S*[0-9a-z])?)/gi, '<a class="rfc" href="https://tools.ietf.org/html/rfc$2$3" title="RFC $2">$1</a>')
  100. .replace(/(urn:isbn:([0-9-]+)(#\S*[0-9a-z])?)/gi, '<a class="isbn" href="https://de.wikipedia.org/wiki/Spezial:ISBN-Suche?isbn=$2" title="ISBN $2">$1</a>')
  101. .replace(/(urn:ean:([0-9-]+)(#\S*[0-9a-z])?)/gi, '<a class="ean" href="https://www.ean-suche.de/?q=$2" title="EAN $2">$1</a>')
  102. .replace(/(CVE-[0-9-]+-[0-9]+)/gi, '<a class="cve" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=$1">$1</a>');
  103. }
  104. }
  105. function adjustIframeHeight(ifrm) {
  106. // https://www.dyn-web.com/tutorials/iframes/height/
  107. function getDocHeight(doc) {
  108. // stackoverflow.com/questions/1145850/
  109. const body = doc.body, html = doc.documentElement;
  110. return Math.max(body.scrollHeight, body.offsetHeight,
  111. html.clientHeight, html.scrollHeight, html.offsetHeight);
  112. }
  113. const doc = ifrm.contentDocument ? ifrm.contentDocument : ifrm.contentWindow.document;
  114. requestAnimationFrame(function() { // http://wilsonpage.co.uk/preventing-layout-thrashing/
  115. // ifrm.style.visibility = 'hidden';
  116. ifrm.style.height = "10px"; // reset to minimal height ...
  117. // IE opt. for bing/msn needs a bit added or scrollbar appears
  118. ifrm.style.height = getDocHeight(doc) + 4 + "px";
  119. // ifrm.style.visibility = 'visible';
  120. });
  121. }
  122. document.documentElement.classList.add('script-active');
  123. document.documentElement.classList.remove('script-inactive');
  124. const xml_base_pub = document.documentElement.getAttribute("data-xml-base-pub");
  125. /* set class logged-out or logged-in */
  126. {
  127. document.documentElement.classList.add('logged-out'); // do in js early on load
  128. // check if we're logged-in (AJAX or Cookie?).
  129. const xhr = new XMLHttpRequest();
  130. xhr.onreadystatechange = function(data0) {
  131. if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
  132. if (this.status === 200) {
  133. document.documentElement.classList.add('logged-in');
  134. document.documentElement.classList.remove('logged-out');
  135. }
  136. // store the result locally and use as initial value for later calls to avoid a logged-in flicker?
  137. }
  138. }
  139. xhr.timeout = 1000;
  140. xhr.open('GET', xml_base_pub + '/../seppo.cgi/session');
  141. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  142. xhr.send();
  143. }
  144. // onload="document.getElementById('q').removeAttribute('autofocus');document.getElementById('post').setAttribute('autofocus', 'autofocus');"
  145. // onload="document.form_post.post.focus();"
  146. const highlight = "highlight";
  147. const shaded = "shaded";
  148. // https://stackoverflow.com/a/69934481/349514
  149. const smooth = { block: 'start', behavior: 'smooth'};
  150. window.onpageshow = (event) => {
  151. const hi = document.getElementById(location.hash.replace(/.*#/,""));
  152. if(hi == null)
  153. return;
  154. if(/^#[0-9]+$/.test(location.hash)) {
  155. document.documentElement.classList.add(shaded);
  156. hi.classList.add(highlight);
  157. }
  158. hi.scrollIntoView(smooth);
  159. };
  160. window.onhashchange = (event) => {
  161. const ol = document.getElementById(event.oldURL.replace(/.*#/,""));
  162. ol.classList.remove(highlight);
  163. const hi = document.getElementById(event.newURL.replace(/.*#/,""));
  164. if(hi == null) {
  165. document.documentElement.classList.remove(shaded);
  166. return;
  167. }
  168. if(/^#[0-9]+$/.test(location.hash)) {
  169. document.documentElement.classList.add(shaded);
  170. hi.classList.add(highlight);
  171. }
  172. hi.scrollIntoView(smooth);
  173. };
  174. // Firefox 56+ doesn't fire that one in xslt situation: document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); });
  175. var addlink;
  176. document.onreadystatechange = function () {
  177. if(addlink !== undefined)
  178. return;
  179. // console.log('setup awesomeplete');
  180. // inspired by http://leaverou.github.io/awesomplete/#extensibility
  181. addlink = new Awesomplete('input[data-multiple]', {
  182. minChars: 3,
  183. maxItems: 15,
  184. filter: function(text, input) { const m = input.match(/#(\S*)$/); return m !== null && Awesomplete.FILTER_CONTAINS(text, m[1]); /* match */ },
  185. item: function(text, input) { const m = input.match(/#(\S*)$/); return m !== null && Awesomplete.ITEM(text, m[1]); /* highlight */ },
  186. replace: function(text) { const inp = this.input; inp.value = inp.value.replace(/#[^#]+$/, text) + " "; },
  187. });
  188. const xhr = new XMLHttpRequest()
  189. xhr.onreadystatechange = function() {
  190. if (this.readyState === XMLHttpRequest.DONE && this.status == 200)
  191. addlink.list = JSON.parse(this.response);
  192. };
  193. xhr.timeout = 1000;
  194. xhr.open('GET', xml_base_pub + '/t/index.json');
  195. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  196. xhr.send();
  197. document.getElementById('q').focus();
  198. computeTagFontsize(document.getElementById('tags'));
  199. loadDeferredImages(document.getElementsByTagName('img'));
  200. clickableTextLinks(document.getElementsByClassName('clickable'));
  201. checkLinkHref(document.getElementsByClassName("enabled"));
  202. {
  203. const ol = document.getElementById('entries').children;
  204. for (li of ol) {
  205. const ifrm = li.getElementsByTagName('iframe')[0];
  206. if (undefined != ifrm)
  207. ifrm.onload = adjustIframeHeight(ifrm);
  208. }
  209. }
  210. /*
  211. // https://koddsson.com/posts/emoji-favicon/
  212. const favicon = document.querySelector("html > head > link[rel=icon]");
  213. if (favicon) {
  214. const emoji = favicon.getAttribute("data-emoji");
  215. if (emoji) {
  216. const canvas = document.createElement("canvas");
  217. canvas.height = 64;
  218. canvas.width = 64;
  219. const ctx = canvas.getContext("2d");
  220. ctx.font = "64px serif";
  221. ctx.fillText(emoji, 0, 56);
  222. favicon.href = canvas.toDataURL();
  223. }
  224. }
  225. */
  226. };