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