1// if jQuery was loaded, let's make it noConflict here. 2if ('function' === typeof jQuery && 'function' === typeof jQuery.noConflict) { 3 jQuery.noConflict(); 4} 5 6/** 7 * Mark a JavaScript function as deprecated 8 * 9 * This will print a warning to the JavaScript console (if available) in 10 * Firebug and Chrome and a stack trace (if available) to easily locate the 11 * problematic function call. 12 * 13 * @param msg optional message to print 14 */ 15function DEPRECATED(msg){ 16 if(!window.console) return; 17 if(!arguments.callee) return; 18 19 var func = arguments.callee.caller.name; 20 var line = 'DEPRECATED function call '+func+'(). '+msg; 21 22 if(console.warn){ 23 console.warn(line); 24 }else{ 25 console.log(line); 26 } 27 28 if(console.trace) console.trace(); 29} 30 31 32/** 33 * Some of these scripts were taken from wikipedia.org and were modified for DokuWiki 34 */ 35 36/** 37 * Some browser detection 38 */ 39var clientPC = navigator.userAgent.toLowerCase(); // Get client info 40var is_macos = navigator.appVersion.indexOf('Mac') != -1; 41var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) && 42 (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1)); 43var is_safari = ((clientPC.indexOf('applewebkit')!=-1) && (clientPC.indexOf('spoofer')==-1)); 44var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled )); 45if (clientPC.indexOf('opera')!=-1) { 46 var is_opera = true; 47 var is_opera_preseven = (window.opera && !document.childNodes); 48 var is_opera_seven = (window.opera && document.childNodes); 49} 50 51/** 52 * Handy shortcut to document.getElementById 53 * 54 * This function was taken from the prototype library 55 * 56 * @link http://prototype.conio.net/ 57 */ 58function $() { 59 DEPRECATED('Please use the JQuery() function instead.'); 60 61 var elements = new Array(); 62 63 for (var i = 0; i < arguments.length; i++) { 64 var element = arguments[i]; 65 if (typeof element == 'string') 66 element = document.getElementById(element); 67 68 if (arguments.length == 1) 69 return element; 70 71 elements.push(element); 72 } 73 74 return elements; 75} 76 77/** 78 * Simple function to check if a global var is defined 79 * 80 * @author Kae Verens 81 * @link http://verens.com/archives/2005/07/25/isset-for-javascript/#comment-2835 82 */ 83function isset(varname){ 84 return(typeof(window[varname])!='undefined'); 85} 86 87/** 88 * Select elements by their class name 89 * 90 * @author Dustin Diaz <dustin [at] dustindiaz [dot] com> 91 * @link http://www.dustindiaz.com/getelementsbyclass/ 92 */ 93function getElementsByClass(searchClass,node,tag) { 94 var classElements = new Array(); 95 if ( node == null ) 96 node = document; 97 if ( tag == null ) 98 tag = '*'; 99 var els = node.getElementsByTagName(tag); 100 var elsLen = els.length; 101 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)"); 102 for (var i = 0, j = 0; i < elsLen; i++) { 103 if ( pattern.test(els[i].className) ) { 104 classElements[j] = els[i]; 105 j++; 106 } 107 } 108 return classElements; 109} 110 111/** 112 * Get the X offset of the top left corner of the given object 113 * 114 * @link http://www.quirksmode.org/js/findpos.html 115 */ 116function findPosX(object){ 117 var curleft = 0; 118 var obj = $(object); 119 if (obj.offsetParent){ 120 do { 121 curleft += obj.offsetLeft; 122 } while (obj = obj.offsetParent); 123 } 124 else if (obj.x){ 125 curleft += obj.x; 126 } 127 return curleft; 128} //end findPosX function 129 130/** 131 * Get the Y offset of the top left corner of the given object 132 * 133 * @link http://www.quirksmode.org/js/findpos.html 134 */ 135function findPosY(object){ 136 var curtop = 0; 137 var obj = $(object); 138 if (obj.offsetParent){ 139 do { 140 curtop += obj.offsetTop; 141 } while (obj = obj.offsetParent); 142 } 143 else if (obj.y){ 144 curtop += obj.y; 145 } 146 return curtop; 147} //end findPosY function 148 149/** 150 * Get the computed style of a node. 151 * 152 * @link https://acidmartin.wordpress.com/2008/08/26/style-get-any-css-property-value-of-an-object/ 153 * @link http://svn.dojotoolkit.org/src/dojo/trunk/_base/html.js 154 */ 155function gcs(node){ 156 if(node.currentStyle){ 157 return node.currentStyle; 158 }else{ 159 return node.ownerDocument.defaultView.getComputedStyle(node, null); 160 } 161} 162 163/** 164 * Escape special chars in JavaScript 165 * 166 * @author Andreas Gohr <andi@splitbrain.org> 167 */ 168function jsEscape(text){ 169 var re=new RegExp("\\\\","g"); 170 text=text.replace(re,"\\\\"); 171 re=new RegExp("'","g"); 172 text=text.replace(re,"\\'"); 173 re=new RegExp('"',"g"); 174 text=text.replace(re,'"'); 175 re=new RegExp("\\\\\\\\n","g"); 176 text=text.replace(re,"\\n"); 177 return text; 178} 179 180/** 181 * This function escapes some special chars 182 * @deprecated by above function 183 */ 184function escapeQuotes(text) { 185 var re=new RegExp("'","g"); 186 text=text.replace(re,"\\'"); 187 re=new RegExp('"',"g"); 188 text=text.replace(re,'"'); 189 re=new RegExp("\\n","g"); 190 text=text.replace(re,"\\n"); 191 return text; 192} 193 194/** 195 * Adds a node as the first childenode to the given parent 196 * 197 * @see appendChild() 198 */ 199function prependChild(parent,element) { 200 if(!parent.firstChild){ 201 parent.appendChild(element); 202 }else{ 203 parent.insertBefore(element,parent.firstChild); 204 } 205} 206 207/** 208 * Prints a animated gif to show the search is performed 209 * 210 * Because we need to modify the DOM here before the document is loaded 211 * and parsed completely we have to rely on document.write() 212 * 213 * @author Andreas Gohr <andi@splitbrain.org> 214 */ 215function showLoadBar(){ 216 217 document.write('<img src="'+DOKU_BASE+'lib/images/loading.gif" '+ 218 'width="150" height="12" alt="..." />'); 219 220 /* this does not work reliable in IE 221 obj = $(id); 222 223 if(obj){ 224 obj.innerHTML = '<img src="'+DOKU_BASE+'lib/images/loading.gif" '+ 225 'width="150" height="12" alt="..." />'; 226 obj.style.display="block"; 227 } 228 */ 229} 230 231/** 232 * Disables the animated gif to show the search is done 233 * 234 * @author Andreas Gohr <andi@splitbrain.org> 235 */ 236function hideLoadBar(id){ 237 obj = $(id); 238 if(obj) obj.style.display="none"; 239} 240 241/** 242 * Adds the toggle switch to the TOC 243 */ 244function addTocToggle() { 245 if(!document.getElementById) return; 246 var header = $('toc__header'); 247 if(!header) return; 248 var toc = $('toc__inside'); 249 250 var obj = document.createElement('span'); 251 obj.id = 'toc__toggle'; 252 obj.style.cursor = 'pointer'; 253 if (toc && toc.style.display == 'none') { 254 obj.innerHTML = '<span>+</span>'; 255 obj.className = 'toc_open'; 256 } else { 257 obj.innerHTML = '<span>−</span>'; 258 obj.className = 'toc_close'; 259 } 260 261 prependChild(header,obj); 262 obj.parentNode.onclick = toggleToc; 263 obj.parentNode.style.cursor = 'pointer'; 264} 265 266/** 267 * This toggles the visibility of the Table of Contents 268 */ 269function toggleToc() { 270 var toc = $('toc__inside'); 271 var obj = $('toc__toggle'); 272 if(toc.style.display == 'none') { 273 toc.style.display = ''; 274 obj.innerHTML = '<span>−</span>'; 275 obj.className = 'toc_close'; 276 } else { 277 toc.style.display = 'none'; 278 obj.innerHTML = '<span>+</span>'; 279 obj.className = 'toc_open'; 280 } 281} 282 283/** 284 * Create JavaScript mouseover popup 285 */ 286function insitu_popup(target, popup_id) { 287 288 // get or create the popup div 289 var fndiv = $(popup_id); 290 if(!fndiv){ 291 fndiv = document.createElement('div'); 292 fndiv.id = popup_id; 293 fndiv.className = 'insitu-footnote JSpopup dokuwiki'; 294 295 // autoclose on mouseout - ignoring bubbled up events 296 addEvent(fndiv,'mouseout',function(e){ 297 var p = e.relatedTarget || e.toElement; 298 while (p && p !== this) { 299 p = p.parentNode; 300 } 301 if (p === this) { 302 return; 303 } 304 // okay, hide it 305 this.style.display='none'; 306 }); 307 getElementsByClass('dokuwiki', document.body, 'div')[0].appendChild(fndiv); 308 } 309 310 var non_static_parent = fndiv.parentNode; 311 while (non_static_parent != document && gcs(non_static_parent)['position'] == 'static') { 312 non_static_parent = non_static_parent.parentNode; 313 } 314 315 var fixed_target_parent = target; 316 while (fixed_target_parent != document && gcs(fixed_target_parent)['position'] != 'fixed') { 317 fixed_target_parent = fixed_target_parent.parentNode; 318 } 319 320 // position the div and make it visible 321 if (fixed_target_parent != document) { 322 // the target has position fixed, that means the footnote needs to be fixed, too 323 fndiv.style.position = 'fixed'; 324 } else { 325 fndiv.style.position = 'absolute'; 326 } 327 328 if (fixed_target_parent != document || non_static_parent == document) { 329 fndiv.style.left = findPosX(target)+'px'; 330 fndiv.style.top = (findPosY(target)+target.offsetHeight * 1.5) + 'px'; 331 } else { 332 fndiv.style.left = (findPosX(target) - findPosX(non_static_parent)) +'px'; 333 fndiv.style.top = (findPosY(target)+target.offsetHeight * 1.5 - findPosY(non_static_parent)) + 'px'; 334 } 335 336 fndiv.style.display = ''; 337 return fndiv; 338} 339 340/** 341 * Display an insitu footnote popup 342 * 343 * @author Andreas Gohr <andi@splitbrain.org> 344 * @author Chris Smith <chris@jalakai.co.uk> 345 */ 346function footnote(e){ 347 var fndiv = insitu_popup(e.target, 'insitu__fn'); 348 349 // locate the footnote anchor element 350 var a = $("fn__" + e.target.id.substr(5)); 351 if (!a){ return; } 352 353 // anchor parent is the footnote container, get its innerHTML 354 var content = new String (a.parentNode.parentNode.innerHTML); 355 356 // strip the leading content anchors and their comma separators 357 content = content.replace(/<sup>.*<\/sup>/gi, ''); 358 content = content.replace(/^\s+(,\s+)+/,''); 359 360 // prefix ids on any elements with "insitu__" to ensure they remain unique 361 content = content.replace(/\bid=(['"])([^"']+)\1/gi,'id="insitu__$2'); 362 363 // now put the content into the wrapper 364 fndiv.innerHTML = content; 365} 366 367/** 368 * Add the event handlers to footnotes 369 * 370 * @author Andreas Gohr <andi@splitbrain.org> 371 */ 372addInitEvent(function(){ 373 var elems = getElementsByClass('fn_top',null,'a'); 374 for(var i=0; i<elems.length; i++){ 375 addEvent(elems[i],'mouseover',function(e){footnote(e);}); 376 } 377}); 378 379/** 380 * Add the edit window size controls 381 */ 382function initSizeCtl(ctlid,edid){ 383 if(!document.getElementById){ return; } 384 385 var ctl = $(ctlid); 386 var textarea = $(edid); 387 if(!ctl || !textarea) return; 388 389 var hgt = DokuCookie.getValue('sizeCtl'); 390 if(hgt){ 391 textarea.style.height = hgt; 392 }else{ 393 textarea.style.height = '300px'; 394 } 395 396 var wrp = DokuCookie.getValue('wrapCtl'); 397 if(wrp){ 398 setWrap(textarea, wrp); 399 } // else use default value 400 401 var l = document.createElement('img'); 402 var s = document.createElement('img'); 403 var w = document.createElement('img'); 404 l.src = DOKU_BASE+'lib/images/larger.gif'; 405 s.src = DOKU_BASE+'lib/images/smaller.gif'; 406 w.src = DOKU_BASE+'lib/images/wrap.gif'; 407 addEvent(l,'click',function(){sizeCtl(edid,100);}); 408 addEvent(s,'click',function(){sizeCtl(edid,-100);}); 409 addEvent(w,'click',function(){toggleWrap(edid);}); 410 ctl.appendChild(l); 411 ctl.appendChild(s); 412 ctl.appendChild(w); 413} 414 415/** 416 * This sets the vertical size of the editbox 417 */ 418function sizeCtl(edid,val){ 419 var textarea = $(edid); 420 var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2)); 421 height += val; 422 textarea.style.height = height+'px'; 423 424 DokuCookie.setValue('sizeCtl',textarea.style.height); 425} 426 427/** 428 * Toggle the wrapping mode of a textarea 429 */ 430function toggleWrap(edid){ 431 var textarea = $(edid); 432 var wrap = textarea.getAttribute('wrap'); 433 if(wrap && wrap.toLowerCase() == 'off'){ 434 setWrap(textarea, 'soft'); 435 }else{ 436 setWrap(textarea, 'off'); 437 } 438 439 DokuCookie.setValue('wrapCtl',textarea.getAttribute('wrap')); 440} 441 442/** 443 * Set the wrapping mode of a textarea 444 * 445 * @author Fluffy Convict <fluffyconvict@hotmail.com> 446 * @author <shutdown@flashmail.com> 447 * @link http://news.hping.org/comp.lang.javascript.archive/12265.html 448 * @link https://bugzilla.mozilla.org/show_bug.cgi?id=41464 449 */ 450function setWrap(textarea, wrapAttrValue){ 451 textarea.setAttribute('wrap', wrapAttrValue); 452 453 // Fix display for mozilla 454 var parNod = textarea.parentNode; 455 var nxtSib = textarea.nextSibling; 456 parNod.removeChild(textarea); 457 parNod.insertBefore(textarea, nxtSib); 458} 459 460/** 461 * Handler to close all open Popups 462 */ 463function closePopups(){ 464 if(!document.getElementById){ return; } 465 466 var divs = document.getElementsByTagName('div'); 467 for(var i=0; i < divs.length; i++){ 468 if(divs[i].className.indexOf('JSpopup') != -1){ 469 divs[i].style.display = 'none'; 470 } 471 } 472} 473 474/** 475 * disable multiple revisions checkboxes if two are checked 476 * 477 * @author Anika Henke <anika@selfthinker.org> 478 */ 479addInitEvent(function(){ 480 var revForm = $('page__revisions'); 481 if (!revForm) return; 482 var elems = revForm.elements; 483 var countTicks = 0; 484 for (var i=0; i<elems.length; i++) { 485 var input1 = elems[i]; 486 if (input1.type=='checkbox') { 487 addEvent(input1,'click',function(e){ 488 if (this.checked) countTicks++; 489 else countTicks--; 490 for (var j=0; j<elems.length; j++) { 491 var input2 = elems[j]; 492 if (countTicks >= 2) input2.disabled = (input2.type=='checkbox' && !input2.checked); 493 else input2.disabled = (input2.type!='checkbox'); 494 } 495 }); 496 input1.checked = false; // chrome reselects on back button which messes up the logic 497 } else if(input1.type=='submit'){ 498 input1.disabled = true; 499 } 500 } 501}); 502 503 504/** 505 * Highlight the section when hovering over the appropriate section edit button 506 * 507 * @author Andreas Gohr <andi@splitbrain.org> 508 */ 509addInitEvent(function(){ 510 var btns = getElementsByClass('btn_secedit',document,'form'); 511 for(var i=0; i<btns.length; i++){ 512 addEvent(btns[i],'mouseover',function(e){ 513 var tgt = this.parentNode; 514 var nr = tgt.className.match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2]; 515 do { 516 tgt = tgt.previousSibling; 517 } while (tgt !== null && typeof tgt.tagName === 'undefined'); 518 if (tgt === null) return; 519 while(typeof tgt.className === 'undefined' || 520 tgt.className.match('(\\s+|^)sectionedit' + nr + '(\\s+|$)') === null) { 521 if (typeof tgt.className !== 'undefined') { 522 tgt.className += ' section_highlight'; 523 } 524 tgt = (tgt.previousSibling !== null) ? tgt.previousSibling : tgt.parentNode; 525 } 526 if (typeof tgt.className !== 'undefined') tgt.className += ' section_highlight'; 527 }); 528 529 addEvent(btns[i],'mouseout',function(e){ 530 var secs = getElementsByClass('section_highlight'); 531 for(var j=0; j<secs.length; j++){ 532 secs[j].className = secs[j].className.replace(/section_highlight/g,''); 533 } 534 }); 535 } 536}); 537 538