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