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