posts.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. function toggle() {
  2. switch(document.cookie) {
  3. case 'dark':
  4. document.cookie = 'light';
  5. break;
  6. case 'light':
  7. document.cookie = '';
  8. break;
  9. default:
  10. document.cookie = 'dark';
  11. break;
  12. }
  13. console.log("uhu: "+document.cookie);
  14. const lst = document.documentElement.classList;
  15. lst.remove('dark');
  16. lst.remove('light');
  17. lst.add(document.cookie);
  18. }
  19. // list tags with font-size in relation to frequency
  20. // https://github.com/sebsauvage/Shaarli/blob/master/index.php#L1254
  21. function computeTagFontsize(tag0) {
  22. if (!tag0)
  23. return;
  24. const fontMin = 8;
  25. const fontMax = 32;
  26. var countMaxLog = Math.log(1);
  27. const tags = tag0.getElementsByTagName('a');
  28. const counts = new Array(tags.length);
  29. const log = {};
  30. for (var i = tags.length - 1; i >= 0; i--) {
  31. const lbl = tags[i].getElementsByClassName('label')[0].textContent;
  32. if ('2018-01-15T12:52' == lbl) {
  33. counts[i] = 1;
  34. continue;
  35. }
  36. const elm = tags[i].getElementsByClassName('count')[0];
  37. const txt = elm.textContent;
  38. var v = log[txt];
  39. if (!v)
  40. log[txt] = v = Math.log(parseInt(txt, 10));
  41. counts[i] = v;
  42. countMaxLog = Math.max(countMaxLog, counts[i]);
  43. }
  44. log.length = 0;
  45. const factor = 1.0 / countMaxLog * (fontMax - fontMin);
  46. requestAnimationFrame(function() { // http://wilsonpage.co.uk/preventing-layout-thrashing/
  47. for (var i = tags.length - 1; i >= 0; i--) {
  48. const k = counts[i];
  49. var v = log[k];
  50. if (!v)
  51. // https://stackoverflow.com/a/3717340
  52. log[k] = v = Math.ceil(k * factor + fontMin) + 'pt';
  53. tags[i].style.fontSize = v;
  54. }
  55. });
  56. }
  57. // https://varvy.com/pagespeed/defer-images.html
  58. function loadDeferredImages(imgsDefer) {
  59. // console.log('loadDeferredImages: ' + imgsDefer.length);
  60. for (var i = imgsDefer.length - 1; i >= 0 ; i--) {
  61. const v = imgsDefer[i].getAttribute('data-src');
  62. if (!v)
  63. continue;
  64. imgsDefer[i].setAttribute('src', v);
  65. }
  66. }
  67. // make http and geo URIs (RFC 5870) clickable + microformat
  68. function clickableTextLinks(elmsRendered) {
  69. // console.log('make http and geo URIs (RFC 5870) clickable + microformat');
  70. for (var i = elmsRendered.length - 1; i >= 0 ; i--) {
  71. const elm = elmsRendered[i];
  72. elm.innerHTML = elm.innerHTML.replace(/(https?:\/\/[^ \t\r\n"']+[^ ?\t\r\n"'.,;()])/gi, '<a rel="noreferrer" class="http" href="$1">$1</a>');
  73. // https://alanstorm.com/url_regex_explained/ \b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))
  74. // elm.innerHTML = elm.innerHTML.replace(/\b(([\w-]+:\/\/?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/)))/gi, '<a rel="noreferrer" class="http" href="$1">$1</a>');
  75. elm.innerHTML = elm.innerHTML.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>');
  76. elm.innerHTML = elm.innerHTML.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>');
  77. elm.innerHTML = elm.innerHTML.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>');
  78. elm.innerHTML = elm.innerHTML.replace(/(CVE-[0-9-]+-[0-9]+)/gi, '<a class="cve" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=$1">$1</a>');
  79. }
  80. }
  81. const xml_base_pub = document.documentElement.getAttribute("data-xml-base-pub");
  82. {
  83. document.documentElement.classList.add('logged-out'); // do in js early on load
  84. // check if we're logged-in (AJAX or Cookie?).
  85. const xhr = new XMLHttpRequest();
  86. xhr.onreadystatechange = function(data0) {
  87. if (this.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
  88. if (this.status === 200) {
  89. document.documentElement.classList.add('logged-in');
  90. document.documentElement.classList.remove('logged-out');
  91. }
  92. // store the result locally and use as initial value for later calls to avoid a logged-in flicker?
  93. }
  94. }
  95. xhr.timeout = 1000;
  96. xhr.open('GET', xml_base_pub + '/../shaarligo.cgi/session/');
  97. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  98. xhr.send();
  99. }
  100. // onload="document.getElementById('q').removeAttribute('autofocus');document.getElementById('post').setAttribute('autofocus', 'autofocus');"
  101. // onload="document.form_post.post.focus();"
  102. // Firefox 56+ doesn't fire that one in xslt situation: document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); });
  103. var addlink;
  104. document.onreadystatechange = function () {
  105. if(addlink !== undefined)
  106. return;
  107. // console.log('setup awesomeplete');
  108. // inspired by http://leaverou.github.io/awesomplete/#extensibility
  109. addlink = new Awesomplete('input[data-multiple]', {
  110. minChars: 3,
  111. maxItems: 15,
  112. filter: function(text, input) { const m = input.match(/#(\S*)$/); return m !== null && Awesomplete.FILTER_CONTAINS(text, m[1]); /* match */ },
  113. item: function(text, input) { const m = input.match(/#(\S*)$/); return m !== null && Awesomplete.ITEM(text, m[1]); /* highlight */ },
  114. replace: function(text) { const inp = this.input; inp.value = inp.value.replace(/#[^#]+$/, text) + " "; },
  115. });
  116. const xhr = new XMLHttpRequest()
  117. xhr.onreadystatechange = function() {
  118. if (this.readyState === XMLHttpRequest.DONE && this.status == 200)
  119. addlink.list = JSON.parse(this.response);
  120. };
  121. xhr.timeout = 1000;
  122. xhr.open('GET', xml_base_pub + '/t/index.json');
  123. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  124. xhr.send();
  125. document.getElementById('q').focus();
  126. computeTagFontsize(document.getElementById('tags'));
  127. loadDeferredImages(document.getElementsByTagName('img'));
  128. clickableTextLinks(document.getElementById('entries').getElementsByClassName('rendered'));
  129. // https://koddsson.com/posts/emoji-favicon/
  130. const favicon = document.querySelector("html > head > link[rel=icon]");
  131. if (favicon) {
  132. const emoji = favicon.getAttribute("data-emoji");
  133. if (emoji) {
  134. const canvas = document.createElement("canvas");
  135. canvas.height = 64;
  136. canvas.width = 64;
  137. const ctx = canvas.getContext("2d");
  138. ctx.font = "64px serif";
  139. ctx.fillText(emoji, 0, 56);
  140. favicon.href = canvas.toDataURL();
  141. }
  142. }
  143. };