1/** 2 * Page scripts for Ad Hominem Info Template 3 * 4 * @author Sascha Leib <sascha@leib.be> 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 */ 7 8/* everything is contained in the $p namespace: */ 9$p = { 10 11 /* called to initialize the entire script */ 12 init: function() { 13 14 $p.cookie_banner.init(); 15 $p.linkinfo.init(); 16 $p.search.init(); 17 $p.togglers.init(); 18 19 }, 20 21 /* link information */ 22 linkinfo: { 23 init: function() { 24 25 /* find all links in the main section */ 26 var main = document.getElementById("main-layout"); 27 var al = main.getElementsByTagName("a"); 28 Array.prototype.forEach.call(al, function (a) { 29 30 Object.entries($p.linkinfo._restURLs).forEach((c) => { 31 var cls = c[0]; 32 if (a.classList.contains(cls)) { 33 a.addEventListener('mouseover', $p.linkinfo._linkHoverCallback); 34 } 35 }); 36 }); 37 }, 38 39 /* pre-defined REST API URLs for different sites. */ 40 /* variables are enclosed in %, allowed vars are: */ 41 /* - basedir = this site's basedir (e.g. "/"), */ 42 /* - id = the data id of the link (internal only) */ 43 /* - ln = the link name (e.g. for Wikipedia links) */ 44 /* types can be 'internal', 'wikimedia', or 'ahtpl' */ 45 /* for other sites using this template. */ 46 _restURLs : { 47 'wikilink1' : { 48 url: '%basedir%lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview', 49 type:'internal' 50 }, 51 'iw_wp' : { 52 url:'https://en.wikipedia.org/api/rest_v1/page/summary/%id%', 53 type:'wikimedia' 54 }, 55 'iw_wpfr' : { 56 url:'https://fr.wikipedia.org/api/rest_v1/page/summary/%id%', 57 type:'wikimedia' 58 }, 59 'iw_wpde' : { 60 url:'https://de.wikipedia.org/api/rest_v1/page/summary/%id%', 61 type:'wikimedia' 62 }, 63 'iw_wpes' : { 64 url:'https://es.wikipedia.org/api/rest_v1/page/summary/%id%', 65 type:'wikimedia' 66 }, 67 'iw_wppl' : { 68 url:'https://pl.wikipedia.org/api/rest_v1/page/summary/%id%', 69 type:'wikimedia' 70 }, 71 'iw_wpja' : { 72 url:'https://it.wikipedia.org/api/rest_v1/page/summary/%id%', 73 type:'wikimedia' 74 }, 75 'iw_wpru' : { 76 url:'https://ru.wikipedia.org/api/rest_v1/page/summary/%id%', 77 type:'wikimedia' 78 }, 79 'iw_meta' : { 80 url:'https://meta.wikipedia.org/api/rest_v1/page/summary/%id%', 81 type:'wikimedia' 82 }, 83 'iw_en' : { 84 url:'https://fallacies.online/wiki/lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview', 85 base:'https://fallacies.online/wiki/', 86 type:'ahtpl' 87 }, 88 'iw_de' : { 89 url:'https://denkfehler.online/wiki/lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview', 90 base:'https://denkfehler.online/wiki/', 91 type:'ahtpl' 92 } 93 }, 94 /* note: this covers the internal links and the most common 95 wikipedia lang versions. If you know about any other 96 relevant sites to be added here, let the author of this 97 template know (ad@hominem.info) */ 98 99 /* TODO: mechanism to dynamically add sites by site admin */ 100 101 /* callback for the onhover event of links: */ 102 _linkHoverCallback: function() { 103 104 var a = jQuery(this); 105 var hi = jQuery.data(this, 'has-info'); 106 var href = jQuery(this).attr('href'); 107 var wid = null; 108 var url = null; 109 var type = ''; 110 111 /* only if the info hasn't been set yet: */ 112 if (hi == undefined || hi == '') { 113 114 // remember that we are now working on the link: 115 jQuery.data(this, 'has-info', '0'); 116 117 // find the URL to query: 118 try { 119 for (var cls in $p.linkinfo._restURLs) { 120 if (a.hasClass(cls)) { 121 url = $p.linkinfo._restURLs[cls].url; 122 type = $p.linkinfo._restURLs[cls].type; 123 break; 124 } 125 }; 126 } catch (e) {} 127 128 /* get the ID to request: */ 129 switch(type) { 130 131 case 'internal': // internal links 132 url = url.replace('%basedir%', (typeof BASEDIR!=='undefined'?BASEDIR:'/')); 133 wid = jQuery(this).data('wiki-id'); 134 break; 135 case 'wikimedia': // wikipedia sites 136 wid = href.substring(href.lastIndexOf('/')+1); 137 break; 138 case 'ahtpl': // Other sites with this template 139 wid = href.substring($p.linkinfo._restURLs[cls].base.length).replaceAll('/', ':'); 140 break; 141 default: // unknown -> skip 142 return; 143 } 144 145 // URL & ID found? 146 if (url !== null && typeof wid !== 'undefined') { 147 148 /* load the page info */ 149 jQuery.ajax({ 150 url: url.replace('%id%', encodeURIComponent(wid)), 151 context: a, 152 dataType: 'json', 153 crossDomain: true, 154 error: function(xhr, msg, e) { 155 console.error(msg); 156 }, 157 success: function(data, msg, xhr) { 158 // build the new title for the element: 159 if (typeof data.title !== 'undefined') { 160 jQuery(this).attr('title', data.title + "\n" + data.extract); 161 jQuery.data(this, 'has-info', '1'); 162 } 163 }, 164 complete: function() { 165 if (jQuery.data(this, 'has-info') == '0') { 166 jQuery.removeData(this, 'has-info'); 167 } 168 } 169 }); 170 } 171 } 172 } 173 }, 174 175 /* anything related to the search */ 176 search: { 177 178 /* initializer */ 179 init: function() { 180 $p.search.gui.init(); 181 }, 182 183 /* the search gui */ 184 gui: { 185 186 _container: null, 187 _elements: { field: null, clear: null, search: null }, 188 189 /* init the gui */ 190 init: function() { 191 192 try { 193 194 /* find all the search elements: */ 195 var form = document.getElementById('dw__search'); 196 197 198 var div = form.getElementsByClassName('search-field')[0]; 199 $p.search.gui._container = div; 200 201 var field = div.getElementsByTagName('input')[0]; 202 $p.search.gui._elements.field = field; 203 field.addEventListener('focus', $p.search.gui.__elementFocus); 204 field.addEventListener('blur', $p.search.gui.__elementBlur); 205 206 var buttons = div.getElementsByTagName('button'); 207 Array.prototype.forEach.call(buttons, function(b) { 208 var type = b.getAttribute('type'); 209 if (type == 'reset') { 210 $p.search.gui._elements.clear = b; 211 } else if (type == 'submit') { 212 $p.search.gui._elements.search = b; 213 } 214 b.addEventListener('focus', $p.search.gui.__elementFocus); 215 b.addEventListener('blur', $p.search.gui.__elementBlur); 216 }); 217 218 } catch (e) { 219 console.warn("Can’t initialize search form."); 220 console.error(e); 221 } 222 }, 223 224 /* call back for fields */ 225 __elementFocus: function() { 226 $p.search.gui._container.classList.add("focus"); 227 }, 228 __elementBlur: function() { 229 $p.search.gui._container.classList.remove("focus"); 230 231 } 232 } 233 }, 234 235 /* expaning sections, for menus, etc. */ 236 togglers: { 237 238 /* initialize togglers */ 239 init: function() { 240 241 const togglers = document.getElementsByClassName("toggle"); 242 243 Array.prototype.forEach.call(togglers, function(t) { 244 245 /* add default state */ 246 if (!(t.classList.contains('show') || (t.classList.contains('hide')))) { 247 t.classList.add('auto'); 248 } 249 250 /* add a callback to the toggler buttons */ 251 var btn = t.getElementsByClassName('tg_button'); 252 Array.prototype.forEach.call(btn, function(b) { 253 b.addEventListener('click', $p.togglers._buttonCallback); 254 b.classList.add('active'); 255 }); 256 257 }); 258 }, 259 260 /* callback for the toggler button click */ 261 _buttonCallback: function() { 262 263 var t = this.parentNode; 264 265 /* current state of the toggler: */ 266 var state = 'auto'; 267 if (t.classList.contains('show')) state = 'show'; 268 if (t.classList.contains('hide')) state = 'hide'; 269 if (t.classList.contains('alt')) state = 'alt'; 270 271 /* set new state: */ 272 var newState = 'alt'; 273 if (state == 'show') { newState = 'hide' } 274 else if (state == 'hide') { newState = 'show' } 275 else if (state == 'alt') { newState = 'auto' } 276 277 t.classList.remove(state); 278 t.classList.add(newState); 279 280 } 281 }, 282 283 /* Cookies info banner */ 284 cookie_banner: { 285 286 /* initialize Cookies info banner */ 287 init: function() { 288 289 // find the cookiebanner elements: 290 var btn = jQuery('#cookiebanner button'); 291 292 var cookie = jQuery.cookie('cookielaw'); 293 294 if ( (cookie !== '1') && (btn.length >= 1) ) { // if found only 295 296 // assign callback: 297 jQuery(btn).click($p.cookie_banner._buttonCallback); 298 299 // show the banner 300 jQuery('#cookiebanner').show(); 301 302 // set focus: 303 jQuery(btn).first().focus(); 304 } 305 }, 306 307 /* callback for the "OK" button */ 308 _buttonCallback: function() { 309 310 const date = new Date(); 311 date.setFullYear(date.getFullYear() + 1); 312 313 var path = ( typeof BASEDIR !== 'undefined' ? BASEDIR : '/'); 314 315 document.cookie = 'cookielaw=1; path=' + path + '; expires=' + date.toUTCString() + '; SameSite=Lax'; 316 jQuery('#cookiebanner').remove(); 317 } 318 } 319}; 320 321/* load the script when the DOM is ready */ 322 323window.addEventListener("DOMContentLoaded", $p.init); 324