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