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