2 * Some of these scripts were taken from wikipedia.org and were modified for DokuWiki
6 * Some browser detection
8 var clientPC = navigator.userAgent.toLowerCase(); // Get client info
9 var is_macos = navigator.appVersion.indexOf('Mac') != -1;
10 var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1) &&
11 (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1));
12 var is_safari = ((clientPC.indexOf('AppleWebKit')!=-1) && (clientPC.indexOf('spoofer')==-1));
13 var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled ));
14 if (clientPC.indexOf('opera')!=-1) {
16 var is_opera_preseven = (window.opera && !document.childNodes);
17 var is_opera_seven = (window.opera && document.childNodes);
21 * Handy shortcut to document.getElementById
23 * This function was taken from the prototype library
25 * @link http://prototype.conio.net/
28 var elements = new Array();
30 for (var i = 0; i < arguments.length; i++) {
31 var element = arguments[i];
32 if (typeof element == 'string')
33 element = document.getElementById(element);
35 if (arguments.length == 1)
38 elements.push(element);
45 * Simple function to check if a global var is defined
48 * @link http://verens.com/archives/2005/07/25/isset-for-javascript/#comment-2835
50 function isset(varname){
51 return(typeof(window[varname])!='undefined');
55 * Select elements by their class name
57 * @author Dustin Diaz <dustin [at] dustindiaz [dot] com>
58 * @link http://www.dustindiaz.com/getelementsbyclass/
60 function getElementsByClass(searchClass,node,tag) {
61 var classElements = new Array();
66 var els = node.getElementsByTagName(tag);
67 var elsLen = els.length;
68 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
69 for (var i = 0, j = 0; i < elsLen; i++) {
70 if ( pattern.test(els[i].className) ) {
71 classElements[j] = els[i];
79 * Get the X offset of the top left corner of the given object
81 * @link http://www.quirksmode.org/index.html?/js/findpos.html
83 function findPosX(object){
86 if (obj.offsetParent){
87 while (obj.offsetParent){
88 curleft += obj.offsetLeft;
89 obj = obj.offsetParent;
96 } //end findPosX function
99 * Get the Y offset of the top left corner of the given object
101 * @link http://www.quirksmode.org/index.html?/js/findpos.html
103 function findPosY(object){
106 if (obj.offsetParent){
107 while (obj.offsetParent){
108 curtop += obj.offsetTop;
109 obj = obj.offsetParent;
116 } //end findPosY function
119 * Escape special chars in JavaScript
121 * @author Andreas Gohr <andi@splitbrain.org>
123 function 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");
136 * This function escapes some special chars
137 * @deprecated by above function
139 function 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");
150 * Adds a node as the first childenode to the given parent
154 function prependChild(parent,element) {
155 if(!parent.firstChild){
156 parent.appendChild(element);
158 parent.insertBefore(element,parent.firstChild);
163 * Prints a animated gif to show the search is performed
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()
168 * @author Andreas Gohr <andi@splitbrain.org>
170 function showLoadBar(){
172 document.write('<img src="'+DOKU_BASE+'lib/images/loading.gif" '+
173 'width="150" height="12" alt="..." />');
175 /* this does not work reliable in IE
179 obj.innerHTML = '<img src="'+DOKU_BASE+'lib/images/loading.gif" '+
180 'width="150" height="12" alt="..." />';
181 obj.style.display="block";
187 * Disables the animated gif to show the search is done
189 * @author Andreas Gohr <andi@splitbrain.org>
191 function hideLoadBar(id){
193 if(obj) obj.style.display="none";
197 * Adds the toggle switch to the TOC
199 function addTocToggle() {
200 if(!document.getElementById) return;
201 var header = $('toc__header');
203 var toc = $('toc__inside');
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';
212 obj.innerHTML = '<span>−</span>';
213 obj.className = 'toc_close';
216 prependChild(header,obj);
217 obj.parentNode.onclick = toggleToc;
219 obj.parentNode.style.cursor = 'pointer';
220 obj.parentNode.style.cursor = 'hand';
225 * This toggles the visibility of the Table of Contents
227 function toggleToc() {
228 var toc = $('toc__inside');
229 var obj = $('toc__toggle');
230 if(toc.style.display == 'none') {
231 toc.style.display = '';
232 obj.innerHTML = '<span>−</span>';
233 obj.className = 'toc_close';
235 toc.style.display = 'none';
236 obj.innerHTML = '<span>+</span>';
237 obj.className = 'toc_open';
242 * Display an insitu footnote popup
244 * @author Andreas Gohr <andi@splitbrain.org>
245 * @author Chris Smith <chris@jalakai.co.uk>
247 function footnote(e){
249 var id = obj.id.substr(5);
251 // get or create the footnote popup div
252 var fndiv = $('insitu__fn');
254 fndiv = document.createElement('div');
255 fndiv.id = 'insitu__fn';
256 fndiv.className = 'insitu-footnote JSpopup dokuwiki';
258 // autoclose on mouseout - ignoring bubbled up events
259 addEvent(fndiv,'mouseout',function(e){
260 if(e.target != fndiv){
264 // check if the element was really left
265 if(e.pageX){ // Mozilla
266 var bx1 = findPosX(fndiv);
267 var bx2 = bx1 + fndiv.offsetWidth;
268 var by1 = findPosY(fndiv);
269 var by2 = by1 + fndiv.offsetHeight;
272 if(x > bx1 && x < bx2 && y > by1 && y < by2){
273 // we're still inside boundaries
278 if(e.offsetX > 0 && e.offsetX < fndiv.offsetWidth-1 &&
279 e.offsetY > 0 && e.offsetY < fndiv.offsetHeight-1){
280 // we're still inside boundaries
286 fndiv.style.display='none';
288 document.body.appendChild(fndiv);
291 // locate the footnote anchor element
292 var a = $( "fn__"+id );
295 // anchor parent is the footnote container, get its innerHTML
296 var content = new String (a.parentNode.parentNode.innerHTML);
298 // strip the leading content anchors and their comma separators
299 content = content.replace(/<sup>.*<\/sup>/gi, '');
300 content = content.replace(/^\s+(,\s+)+/,'');
302 // prefix ids on any elements with "insitu__" to ensure they remain unique
303 content = content.replace(/\bid=\"(.*?)\"/gi,'id="insitu__$1');
305 // now put the content into the wrapper
306 fndiv.innerHTML = content;
308 // position the div and make it visible
310 if(e.pageX){ // Mozilla
317 fndiv.style.position = 'absolute';
318 fndiv.style.left = (x+2)+'px';
319 fndiv.style.top = (y+2)+'px';
320 fndiv.style.display = '';
324 * Add the event handlers to footnotes
326 * @author Andreas Gohr <andi@splitbrain.org>
328 addInitEvent(function(){
329 var elems = getElementsByClass('fn_top',null,'a');
330 for(var i=0; i<elems.length; i++){
331 addEvent(elems[i],'mouseover',function(e){footnote(e);});
336 * Add the edit window size controls
338 function initSizeCtl(ctlid,edid){
339 if(!document.getElementById){ return; }
342 var textarea = $(edid);
343 if(!ctl || !textarea) return;
345 var hgt = DokuCookie.getValue('sizeCtl');
347 textarea.style.height = hgt;
349 textarea.style.height = '300px';
352 var wrp = DokuCookie.getValue('wrapCtl');
354 setWrap(textarea, wrp);
355 } // else use default value
357 var l = document.createElement('img');
358 var s = document.createElement('img');
359 var w = document.createElement('img');
360 l.src = DOKU_BASE+'lib/images/larger.gif';
361 s.src = DOKU_BASE+'lib/images/smaller.gif';
362 w.src = DOKU_BASE+'lib/images/wrap.gif';
363 addEvent(l,'click',function(){sizeCtl(edid,100);});
364 addEvent(s,'click',function(){sizeCtl(edid,-100);});
365 addEvent(w,'click',function(){toggleWrap(edid);});
372 * This sets the vertical size of the editbox
374 function sizeCtl(edid,val){
375 var textarea = $(edid);
376 var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2));
378 textarea.style.height = height+'px';
380 DokuCookie.setValue('sizeCtl',textarea.style.height);
384 * Toggle the wrapping mode of a textarea
386 function toggleWrap(edid){
387 var textarea = $(edid);
388 var wrap = textarea.getAttribute('wrap');
389 if(wrap && wrap.toLowerCase() == 'off'){
390 setWrap(textarea, 'soft');
392 setWrap(textarea, 'off');
395 DokuCookie.setValue('wrapCtl',textarea.getAttribute('wrap'));
399 * Set the wrapping mode of a textarea
401 * @author Fluffy Convict <fluffyconvict@hotmail.com>
402 * @author <shutdown@flashmail.com>
403 * @link http://news.hping.org/comp.lang.javascript.archive/12265.html
404 * @link https://bugzilla.mozilla.org/show_bug.cgi?id=41464
406 function setWrap(textarea, wrapAttrValue){
407 textarea.setAttribute('wrap', wrapAttrValue);
409 // Fix display for mozilla
410 var parNod = textarea.parentNode;
411 var nxtSib = textarea.nextSibling;
412 parNod.removeChild(textarea);
413 parNod.insertBefore(textarea, nxtSib);
417 * Handler to close all open Popups
419 function closePopups(){
420 if(!document.getElementById){ return; }
422 var divs = document.getElementsByTagName('div');
423 for(var i=0; i < divs.length; i++){
424 if(divs[i].className.indexOf('JSpopup') != -1){
425 divs[i].style.display = 'none';
431 * Looks for an element with the ID scroll__here at scrolls to it
433 function scrollToMarker(){
434 var obj = $('scroll__here');
435 if(obj) obj.scrollIntoView();
439 * Looks for an element with the ID focus__this at sets focus to it
441 function focusMarker(){
442 var obj = $('focus__this');
449 function cleanMsgArea(){
450 var elems = getElementsByClass('(success|info|error)',document,'div');
452 for(var i=0; i<elems.length; i++){
453 elems[i].style.display = 'none';
459 * disable multiple revisions checkboxes if two are checked
461 * @author Anika Henke <anika@selfthinker.org>
463 addInitEvent(function(){
464 var revForm = $('page__revisions');
465 if (!revForm) return;
466 var elems = revForm.elements;
468 for (var i=0; i<elems.length; i++) {
469 var input1 = elems[i];
470 if (input1.type=='checkbox') {
471 addEvent(input1,'click',function(e){
472 if (this.checked) countTicks++;
474 for (var j=0; j<elems.length; j++) {
475 var input2 = elems[j];
476 if (countTicks >= 2) input2.disabled = (input2.type=='checkbox' && !input2.checked);
477 else input2.disabled = (input2.type!='checkbox');
480 input1.checked = false; // chrome reselects on back button which messes up the logic
481 } else if(input1.type=='submit'){
482 input1.disabled = true;
488 * Add the event handler to the actiondropdown
490 * @author Andreas Gohr <andi@splitbrain.org>
492 addInitEvent(function(){
493 var selector = $('action__selector');
494 if(!selector) return;
496 addEvent(selector,'change',function(e){
500 $('action__selectorbtn').style.display = 'none';
504 * Display error for Windows Shares on browsers other than IE
506 * @author Michael Klier <chi@chimeric.de>
508 function checkWindowsShares() {
509 if(!LANG['nosmblinks']) return true;
510 var elems = getElementsByClass('windows',document,'a');
512 for(var i=0; i<elems.length; i++){
513 var share = elems[i];
514 addEvent(share,'click',function(){
515 if(document.all == null) {
516 alert(LANG['nosmblinks']);
524 * Add the event handler for the Windows Shares check
526 * @author Michael Klier <chi@chimeric.de>
528 addInitEvent(function(){
529 checkWindowsShares();
533 * Highlight the section when hovering over the appropriate section edit button
535 * @author Andreas Gohr <andi@splitbrain.org>
537 addInitEvent(function(){
538 var break_classes = new RegExp('secedit|toc|page');
539 var btns = getElementsByClass('btn_secedit',document,'form');
540 for(var i=0; i<btns.length; i++){
541 addEvent(btns[i],'mouseover',function(e){
543 if(tgt.form) tgt = tgt.form;
544 tgt = tgt.parentNode.previousSibling;
545 if(tgt.nodeName != "DIV") tgt = tgt.previousSibling;
546 while(!break_classes.test(tgt.className)) {
547 tgt.className += ' section_highlight';
548 if (tgt.tagName == 'H1') break;
549 tgt = (tgt.previousSibling != null) ? tgt.previousSibling : tgt.parentNode;
553 addEvent(btns[i],'mouseout',function(e){
554 var secs = getElementsByClass('section_highlight');
555 for(var j=0; j<secs.length; j++){
556 secs[j].className = secs[j].className.replace(/section_highlight/,'');
558 var secs = getElementsByClass('section_highlight');