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 obj = document.createElement('span'); 247 obj.id = 'toc__toggle'; 248 obj.innerHTML = '<span>−</span>'; 249 obj.className = 'toc_close'; 250 obj.style.cursor = 'pointer'; 251 252 prependChild(header,obj); 253 obj.parentNode.onclick = toggleToc; 254 try { 255 obj.parentNode.style.cursor = 'pointer'; 256 obj.parentNode.style.cursor = 'hand'; 257 }catch(e){} 258} 259 260/** 261 * This toggles the visibility of the Table of Contents 262 */ 263function toggleToc() { 264 var toc = $('toc__inside'); 265 var obj = $('toc__toggle'); 266 if(toc.style.display == 'none') { 267 toc.style.display = ''; 268 obj.innerHTML = '<span>−</span>'; 269 obj.className = 'toc_close'; 270 } else { 271 toc.style.display = 'none'; 272 obj.innerHTML = '<span>+</span>'; 273 obj.className = 'toc_open'; 274 } 275} 276 277/** 278 * This enables/disables checkboxes for acl-administration 279 * 280 * @author Frank Schubert <frank@schokilade.de> 281 */ 282function checkAclLevel(){ 283 if(document.getElementById) { 284 var scope = $('acl_scope').value; 285 286 //check for namespace 287 if( (scope.indexOf(":*") > 0) || (scope == "*") ){ 288 document.getElementsByName('acl_checkbox[4]')[0].disabled=false; 289 document.getElementsByName('acl_checkbox[8]')[0].disabled=false; 290 }else{ 291 document.getElementsByName('acl_checkbox[4]')[0].checked=false; 292 document.getElementsByName('acl_checkbox[8]')[0].checked=false; 293 294 document.getElementsByName('acl_checkbox[4]')[0].disabled=true; 295 document.getElementsByName('acl_checkbox[8]')[0].disabled=true; 296 } 297 } 298} 299 300/** 301 * Display an insitu footnote popup 302 * 303 * @author Andreas Gohr <andi@splitbrain.org> 304 * @author Chris Smith <chris@jalakai.co.uk> 305 */ 306function footnote(e){ 307 var obj = e.target; 308 var id = obj.id.substr(5); 309 310 // get or create the footnote popup div 311 var fndiv = $('insitu__fn'); 312 if(!fndiv){ 313 fndiv = document.createElement('div'); 314 fndiv.id = 'insitu__fn'; 315 fndiv.className = 'insitu-footnote JSpopup dokuwiki'; 316 317 // autoclose on mouseout - ignoring bubbled up events 318 addEvent(fndiv,'mouseout',function(e){ 319 if(e.target != fndiv){ 320 e.stopPropagation(); 321 return; 322 } 323 // check if the element was really left 324 if(e.pageX){ // Mozilla 325 var bx1 = findPosX(fndiv); 326 var bx2 = bx1 + fndiv.offsetWidth; 327 var by1 = findPosY(fndiv); 328 var by2 = by1 + fndiv.offsetHeight; 329 var x = e.pageX; 330 var y = e.pageY; 331 if(x > bx1 && x < bx2 && y > by1 && y < by2){ 332 // we're still inside boundaries 333 e.stopPropagation(); 334 return; 335 } 336 }else{ // IE 337 if(e.offsetX > 0 && e.offsetX < fndiv.offsetWidth-1 && 338 e.offsetY > 0 && e.offsetY < fndiv.offsetHeight-1){ 339 // we're still inside boundaries 340 e.stopPropagation(); 341 return; 342 } 343 } 344 // okay, hide it 345 fndiv.style.display='none'; 346 }); 347 document.body.appendChild(fndiv); 348 } 349 350 // locate the footnote anchor element 351 var a = $( "fn__"+id ); 352 if (!a){ return; } 353 354 // anchor parent is the footnote container, get its innerHTML 355 var content = new String (a.parentNode.innerHTML); 356 357 // strip the leading content anchors and their comma separators 358 content = content.replace(/<a\s.*?href=\".*\#fnt__\d+\".*?<\/a>/gi, ''); 359 content = content.replace(/^\s+(,\s+)+/,''); 360 361 // prefix ids on any elements with "insitu__" to ensure they remain unique 362 content = content.replace(/\bid=\"(.*?)\"/gi,'id="insitu__$1'); 363 364 // now put the content into the wrapper 365 fndiv.innerHTML = content; 366 367 // position the div and make it visible 368 var x; var y; 369 if(e.pageX){ // Mozilla 370 x = e.pageX; 371 y = e.pageY; 372 }else{ // IE 373 x = e.offsetX; 374 y = e.offsetY; 375 } 376 fndiv.style.position = 'absolute'; 377 fndiv.style.left = (x+2)+'px'; 378 fndiv.style.top = (y+2)+'px'; 379 fndiv.style.display = ''; 380} 381 382/** 383 * Add the event handlers to footnotes 384 * 385 * @author Andreas Gohr <andi@splitbrain.org> 386 */ 387addInitEvent(function(){ 388 var elems = getElementsByClass('fn_top',null,'a'); 389 for(var i=0; i<elems.length; i++){ 390 addEvent(elems[i],'mouseover',function(e){footnote(e);}); 391 } 392}); 393 394/** 395 * Add the edit window size controls 396 */ 397function initSizeCtl(ctlid,edid){ 398 if(!document.getElementById){ return; } 399 400 var ctl = $(ctlid); 401 var textarea = $(edid); 402 if(!ctl || !textarea) return; 403 404 var hgt = DokuCookie.getValue('sizeCtl'); 405 if(hgt){ 406 textarea.style.height = hgt; 407 }else{ 408 textarea.style.height = '300px'; 409 } 410 411 var l = document.createElement('img'); 412 var s = document.createElement('img'); 413 var w = document.createElement('img'); 414 l.src = DOKU_BASE+'lib/images/larger.gif'; 415 s.src = DOKU_BASE+'lib/images/smaller.gif'; 416 w.src = DOKU_BASE+'lib/images/wrap.gif'; 417 addEvent(l,'click',function(){sizeCtl(edid,100);}); 418 addEvent(s,'click',function(){sizeCtl(edid,-100);}); 419 addEvent(w,'click',function(){toggleWrap(edid);}); 420 ctl.appendChild(l); 421 ctl.appendChild(s); 422 ctl.appendChild(w); 423} 424 425/** 426 * This sets the vertical size of the editbox 427 */ 428function sizeCtl(edid,val){ 429 var textarea = $(edid); 430 var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2)); 431 height += val; 432 textarea.style.height = height+'px'; 433 434 DokuCookie.setValue('sizeCtl',textarea.style.height); 435} 436 437/** 438 * Toggle the wrapping mode of a textarea 439 * 440 * @author Fluffy Convict <fluffyconvict@hotmail.com> 441 * @link http://news.hping.org/comp.lang.javascript.archive/12265.html 442 * @author <shutdown@flashmail.com> 443 * @link https://bugzilla.mozilla.org/show_bug.cgi?id=302710#c2 444 */ 445function toggleWrap(edid){ 446 var txtarea = $(edid); 447 var wrap = txtarea.getAttribute('wrap'); 448 if(wrap && wrap.toLowerCase() == 'off'){ 449 txtarea.setAttribute('wrap', 'soft'); 450 }else{ 451 txtarea.setAttribute('wrap', 'off'); 452 } 453 // Fix display for mozilla 454 var parNod = txtarea.parentNode; 455 var nxtSib = txtarea.nextSibling; 456 parNod.removeChild(txtarea); 457 parNod.insertBefore(txtarea, nxtSib); 458} 459 460/** 461 * Handler to close all open Popups 462 */ 463function closePopups(){ 464 if(!document.getElementById){ return; } 465 466 var divs = document.getElementsByTagName('div'); 467 for(var i=0; i < divs.length; i++){ 468 if(divs[i].className.indexOf('JSpopup') != -1){ 469 divs[i].style.display = 'none'; 470 } 471 } 472} 473 474/** 475 * Looks for an element with the ID scroll__here at scrolls to it 476 */ 477function scrollToMarker(){ 478 var obj = $('scroll__here'); 479 if(obj) obj.scrollIntoView(); 480} 481 482/** 483 * Looks for an element with the ID focus__this at sets focus to it 484 */ 485function focusMarker(){ 486 var obj = $('focus__this'); 487 if(obj) obj.focus(); 488} 489 490/** 491 * Remove messages 492 */ 493function cleanMsgArea(){ 494 var elems = getElementsByClass('(success|info|error)',document,'div'); 495 if(elems){ 496 for(var i=0; i<elems.length; i++){ 497 elems[i].style.display = 'none'; 498 } 499 } 500} 501