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