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