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 * Rewrite the accesskey tooltips to be more browser and OS specific. 22 * 23 * Accesskey tooltips are still only a best-guess of what will work 24 * on well known systems. 25 * 26 * @author Ben Coburn <btcoburn@silicodon.net> 27 */ 28function updateAccessKeyTooltip() { 29 // determin tooltip text (order matters) 30 var tip = 'ALT+'; //default 31 if (is_macos) { tip = 'CTRL+'; } 32 if (is_opera) { tip = 'SHIFT+ESC '; } 33 // add other cases here... 34 35 // do tooltip update 36 if (tip=='ALT+') { return; } 37 var exp = /\[ALT\+/i; 38 var rep = '['+tip; 39 40 var elements = document.getElementsByTagName('a'); 41 for (var i=0; i<elements.length; i++) { 42 if (elements[i].accessKey.length==1 && elements[i].title.length>0) { 43 elements[i].title = elements[i].title.replace(exp, rep); 44 } 45 } 46 47 elements = document.getElementsByTagName('input'); 48 for (var i=0; i<elements.length; i++) { 49 if (elements[i].accessKey.length==1 && elements[i].title.length>0) { 50 elements[i].title = elements[i].title.replace(exp, rep); 51 } 52 } 53 54 elements = document.getElementsByTagName('button'); 55 for (var i=0; i<elements.length; i++) { 56 if (elements[i].accessKey.length==1 && elements[i].title.length>0) { 57 elements[i].title = elements[i].title.replace(exp, rep); 58 } 59 } 60} 61 62/** 63 * Handy shortcut to document.getElementById 64 * 65 * This function was taken from the prototype library 66 * 67 * @link http://prototype.conio.net/ 68 */ 69function $() { 70 var elements = new Array(); 71 72 for (var i = 0; i < arguments.length; i++) { 73 var element = arguments[i]; 74 if (typeof element == 'string') 75 element = document.getElementById(element); 76 77 if (arguments.length == 1) 78 return element; 79 80 elements.push(element); 81 } 82 83 return elements; 84} 85 86/** 87 * Simple function to check if a global var is defined 88 * 89 * @author Kae Verens 90 * @link http://verens.com/archives/2005/07/25/isset-for-javascript/#comment-2835 91 */ 92function isset(varname){ 93 return(typeof(window[varname])!='undefined'); 94} 95 96/** 97 * Select elements by their class name 98 * 99 * @author Dustin Diaz <dustin [at] dustindiaz [dot] com> 100 * @link http://www.dustindiaz.com/getelementsbyclass/ 101 */ 102function getElementsByClass(searchClass,node,tag) { 103 var classElements = new Array(); 104 if ( node == null ) 105 node = document; 106 if ( tag == null ) 107 tag = '*'; 108 var els = node.getElementsByTagName(tag); 109 var elsLen = els.length; 110 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)"); 111 for (i = 0, j = 0; i < elsLen; i++) { 112 if ( pattern.test(els[i].className) ) { 113 classElements[j] = els[i]; 114 j++; 115 } 116 } 117 return classElements; 118} 119 120/** 121 * Get the X offset of the top left corner of the given object 122 * 123 * @link http://www.quirksmode.org/index.html?/js/findpos.html 124 */ 125function findPosX(object){ 126 var curleft = 0; 127 var obj = $(object); 128 if (obj.offsetParent){ 129 while (obj.offsetParent){ 130 curleft += obj.offsetLeft; 131 obj = obj.offsetParent; 132 } 133 } 134 else if (obj.x){ 135 curleft += obj.x; 136 } 137 return curleft; 138} //end findPosX function 139 140/** 141 * Get the Y offset of the top left corner of the given object 142 * 143 * @link http://www.quirksmode.org/index.html?/js/findpos.html 144 */ 145function findPosY(object){ 146 var curtop = 0; 147 var obj = $(object); 148 if (obj.offsetParent){ 149 while (obj.offsetParent){ 150 curtop += obj.offsetTop; 151 obj = obj.offsetParent; 152 } 153 } 154 else if (obj.y){ 155 curtop += obj.y; 156 } 157 return curtop; 158} //end findPosY function 159 160/** 161 * Escape special chars in JavaScript 162 * 163 * @author Andreas Gohr <andi@splitbrain.org> 164 */ 165function jsEscape(text){ 166 var re=new RegExp("\\\\","g"); 167 text=text.replace(re,"\\\\"); 168 re=new RegExp("'","g"); 169 text=text.replace(re,"\\'"); 170 re=new RegExp('"',"g"); 171 text=text.replace(re,'"'); 172 re=new RegExp("\\\\\\\\n","g"); 173 text=text.replace(re,"\\n"); 174 return text; 175} 176 177/** 178 * This function escapes some special chars 179 * @deprecated by above function 180 */ 181function escapeQuotes(text) { 182 var re=new RegExp("'","g"); 183 text=text.replace(re,"\\'"); 184 re=new RegExp('"',"g"); 185 text=text.replace(re,'"'); 186 re=new RegExp("\\n","g"); 187 text=text.replace(re,"\\n"); 188 return text; 189} 190 191/** 192 * Adds a node as the first childenode to the given parent 193 * 194 * @see appendChild() 195 */ 196function prependChild(parent,element) { 197 if(!parent.firstChild){ 198 parent.appendChild(element); 199 }else{ 200 parent.insertBefore(element,parent.firstChild); 201 } 202} 203 204/** 205 * Prints a animated gif to show the search is performed 206 * 207 * Because we need to modify the DOM here before the document is loaded 208 * and parsed completely we have to rely on document.write() 209 * 210 * @author Andreas Gohr <andi@splitbrain.org> 211 */ 212function showLoadBar(){ 213 214 document.write('<img src="'+DOKU_BASE+'lib/images/loading.gif" '+ 215 'width="150" height="12" alt="..." />'); 216 217 /* this does not work reliable in IE 218 obj = $(id); 219 220 if(obj){ 221 obj.innerHTML = '<img src="'+DOKU_BASE+'lib/images/loading.gif" '+ 222 'width="150" height="12" alt="..." />'; 223 obj.style.display="block"; 224 } 225 */ 226} 227 228/** 229 * Disables the animated gif to show the search is done 230 * 231 * @author Andreas Gohr <andi@splitbrain.org> 232 */ 233function hideLoadBar(id){ 234 obj = $(id); 235 if(obj) obj.style.display="none"; 236} 237 238/** 239 * Adds the toggle switch to the TOC 240 */ 241function addTocToggle() { 242 if(!document.getElementById) return; 243 var header = $('toc__header'); 244 if(!header) return; 245 246 var showimg = document.createElement('img'); 247 showimg.id = 'toc__show'; 248 showimg.src = DOKU_BASE+'lib/images/arrow_down.gif'; 249 showimg.alt = '+'; 250 showimg.onclick = toggleToc; 251 showimg.style.display = 'none'; 252 253 var hideimg = document.createElement('img'); 254 hideimg.id = 'toc__hide'; 255 hideimg.src = DOKU_BASE+'lib/images/arrow_up.gif'; 256 hideimg.alt = '-'; 257 hideimg.onclick = toggleToc; 258 259 prependChild(header,showimg); 260 prependChild(header,hideimg); 261} 262 263/** 264 * This toggles the visibility of the Table of Contents 265 */ 266function toggleToc() { 267 var toc = $('toc__inside'); 268 var showimg = $('toc__show'); 269 var hideimg = $('toc__hide'); 270 if(toc.style.display == 'none') { 271 toc.style.display = ''; 272 hideimg.style.display = ''; 273 showimg.style.display = 'none'; 274 } else { 275 toc.style.display = 'none'; 276 hideimg.style.display = 'none'; 277 showimg.style.display = ''; 278 } 279} 280 281/** 282 * This enables/disables checkboxes for acl-administration 283 * 284 * @author Frank Schubert <frank@schokilade.de> 285 */ 286function checkAclLevel(){ 287 if(document.getElementById) { 288 var scope = $('acl_scope').value; 289 290 //check for namespace 291 if( (scope.indexOf(":*") > 0) || (scope == "*") ){ 292 document.getElementsByName('acl_checkbox[4]')[0].disabled=false; 293 document.getElementsByName('acl_checkbox[8]')[0].disabled=false; 294 }else{ 295 document.getElementsByName('acl_checkbox[4]')[0].checked=false; 296 document.getElementsByName('acl_checkbox[8]')[0].checked=false; 297 298 document.getElementsByName('acl_checkbox[4]')[0].disabled=true; 299 document.getElementsByName('acl_checkbox[8]')[0].disabled=true; 300 } 301 } 302} 303 304/** 305 * Display an insitu footnote popup 306 * 307 * @author Andreas Gohr <andi@splitbrain.org> 308 * @author Chris Smith <chris@jalakai.co.uk> 309 */ 310function footnote(e){ 311 var obj = e.target; 312 var id = obj.id.substr(5); 313 314 // get or create the footnote popup div 315 var fndiv = $('insitu__fn'); 316 if(!fndiv){ 317 fndiv = document.createElement('div'); 318 fndiv.id = 'insitu__fn'; 319 fndiv.className = 'insitu-footnote JSpopup dokuwiki'; 320 321 // autoclose on mouseout - ignoring bubbled up events 322 addEvent(fndiv,'mouseout',function(e){ 323 if(e.target != fndiv){ 324 e.stopPropagation(); 325 return; 326 } 327 // check if the element was really left 328 if(e.pageX){ // Mozilla 329 var bx1 = findPosX(fndiv); 330 var bx2 = bx1 + fndiv.offsetWidth; 331 var by1 = findPosY(fndiv); 332 var by2 = by1 + fndiv.offsetHeight; 333 var x = e.pageX; 334 var y = e.pageY; 335 if(x > bx1 && x < bx2 && y > by1 && y < by2){ 336 // we're still inside boundaries 337 e.stopPropagation(); 338 return; 339 } 340 }else{ // IE 341 if(e.offsetX > 0 && e.offsetX < fndiv.offsetWidth-1 && 342 e.offsetY > 0 && e.offsetY < fndiv.offsetHeight-1){ 343 // we're still inside boundaries 344 e.stopPropagation(); 345 return; 346 } 347 } 348 // okay, hide it 349 fndiv.style.display='none'; 350 }); 351 document.body.appendChild(fndiv); 352 } 353 354 // locate the footnote anchor element 355 var a = $( "fn__"+id ); 356 if (!a){ return; } 357 358 // anchor parent is the footnote container, get its innerHTML 359 var content = new String (a.parentNode.innerHTML); 360 361 // strip the leading content anchors and their comma separators 362 content = content.replace(/<a\s.*?href=\".*\#fnt__\d+\".*?<\/a>/gi, ''); 363 content = content.replace(/^\s+(,\s+)+/,''); 364 365 // prefix ids on any elements with "insitu__" to ensure they remain unique 366 content = content.replace(/\bid=\"(.*?)\"/gi,'id="insitu__$1'); 367 368 // now put the content into the wrapper 369 fndiv.innerHTML = content; 370 371 // position the div and make it visible 372 var x; var y; 373 if(e.pageX){ // Mozilla 374 x = e.pageX; 375 y = e.pageY; 376 }else{ // IE 377 x = e.offsetX; 378 y = e.offsetY; 379 } 380 fndiv.style.position = 'absolute'; 381 fndiv.style.left = (x+2)+'px'; 382 fndiv.style.top = (y+2)+'px'; 383 fndiv.style.display = ''; 384} 385 386/** 387 * Add the event handlers to footnotes 388 * 389 * @author Andreas Gohr <andi@splitbrain.org> 390 */ 391addInitEvent(function(){ 392 var elems = getElementsByClass('fn_top',null,'a'); 393 for(var i=0; i<elems.length; i++){ 394 addEvent(elems[i],'mouseover',function(e){footnote(e);}); 395 } 396}); 397 398/** 399 * Add the edit window size controls 400 */ 401function initSizeCtl(ctlid,edid){ 402 if(!document.getElementById){ return; } 403 404 var ctl = $(ctlid); 405 var textarea = $(edid); 406 if(!ctl || !textarea) return; 407 408 var hgt = DokuCookie.getValue('sizeCtl'); 409 if(hgt){ 410 textarea.style.height = hgt; 411 }else{ 412 textarea.style.height = '300px'; 413 } 414 415 var l = document.createElement('img'); 416 var s = document.createElement('img'); 417 var w = document.createElement('img'); 418 l.src = DOKU_BASE+'lib/images/larger.gif'; 419 s.src = DOKU_BASE+'lib/images/smaller.gif'; 420 w.src = DOKU_BASE+'lib/images/wrap.gif'; 421 addEvent(l,'click',function(){sizeCtl(edid,100);}); 422 addEvent(s,'click',function(){sizeCtl(edid,-100);}); 423 addEvent(w,'click',function(){toggleWrap(edid);}); 424 ctl.appendChild(l); 425 ctl.appendChild(s); 426 ctl.appendChild(w); 427} 428 429/** 430 * This sets the vertical size of the editbox 431 */ 432function sizeCtl(edid,val){ 433 var textarea = $(edid); 434 var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2)); 435 height += val; 436 textarea.style.height = height+'px'; 437 438 DokuCookie.setValue('sizeCtl',textarea.style.height); 439} 440 441/** 442 * Toggle the wrapping mode of a textarea 443 * 444 * @author Fluffy Convict <fluffyconvict@hotmail.com> 445 * @link http://news.hping.org/comp.lang.javascript.archive/12265.html 446 * @author <shutdown@flashmail.com> 447 * @link https://bugzilla.mozilla.org/show_bug.cgi?id=302710#c2 448 */ 449function toggleWrap(edid){ 450 var txtarea = $(edid); 451 var wrap = txtarea.getAttribute('wrap'); 452 if(wrap && wrap.toLowerCase() == 'off'){ 453 txtarea.setAttribute('wrap', 'soft'); 454 }else{ 455 txtarea.setAttribute('wrap', 'off'); 456 } 457 // Fix display for mozilla 458 var parNod = txtarea.parentNode; 459 var nxtSib = txtarea.nextSibling; 460 parNod.removeChild(txtarea); 461 parNod.insertBefore(txtarea, nxtSib); 462} 463 464/** 465 * Handler to close all open Popups 466 */ 467function closePopups(){ 468 if(!document.getElementById){ return; } 469 470 var divs = document.getElementsByTagName('div'); 471 for(var i=0; i < divs.length; i++){ 472 if(divs[i].className.indexOf('JSpopup') != -1){ 473 divs[i].style.display = 'none'; 474 } 475 } 476} 477 478/** 479 * Looks for an element with the ID scroll__here at scrolls to it 480 */ 481function scrollToMarker(){ 482 var obj = $('scroll__here'); 483 if(obj) obj.scrollIntoView(); 484} 485 486/** 487 * Looks for an element with the ID focus__this at sets focus to it 488 */ 489function focusMarker(){ 490 var obj = $('focus__this'); 491 if(obj) obj.focus(); 492} 493 494/** 495 * Remove messages 496 */ 497function cleanMsgArea(){ 498 var elems = getElementsByClass('(success|info|error)',document,'div'); 499 if(elems){ 500 for(var i=0; i<elems.length; i++){ 501 elems[i].style.display = 'none'; 502 } 503 } 504} 505