xref: /dokuwiki/lib/scripts/script.js (revision ee33a34725046a56589daea1b2957f357d1836aa)
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_gecko  = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1)
10                && (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1));
11var is_safari = ((clientPC.indexOf('AppleWebKit')!=-1) && (clientPC.indexOf('spoofer')==-1));
12var is_khtml  = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled ));
13if (clientPC.indexOf('opera')!=-1) {
14    var is_opera = true;
15    var is_opera_preseven = (window.opera && !document.childNodes);
16    var is_opera_seven = (window.opera && document.childNodes);
17}
18
19
20/**
21 * This function escapes some special chars
22 */
23function escapeQuotes(text) {
24  var re=new RegExp("'","g");
25  text=text.replace(re,"\\'");
26  re=new RegExp('"',"g");
27  text=text.replace(re,'"');
28  re=new RegExp("\\n","g");
29  text=text.replace(re,"\\n");
30  return text;
31}
32
33/**
34 * Prints a animated gif to show the search is performed
35 *
36 * @author Andreas Gohr <andi@splitbrain.org>
37 */
38function showLoadBar(){
39  if(document.getElementById){
40    document.write('<img src="'+DOKU_BASE+'lib/images/loading.gif" '+
41                   'width="150" height="12" id="loading" />');
42  }
43}
44
45/**
46 * Disables the animated gif to show the search is done
47 *
48 * @author Andreas Gohr <andi@splitbrain.org>
49 */
50function hideLoadBar(){
51  if(document.getElementById){
52    document.getElementById('loading').style.display="none";
53  }
54}
55
56/**
57 * Checks if a summary was entered - if not the style is changed
58 *
59 * @author Andreas Gohr <andi@splitbrain.org>
60 */
61function summaryCheck(){
62  if(document.getElementById){
63    var sum = document.getElementById('summary');
64    if(sum.value == ''){
65      sum.className='missing';
66    }else{
67      sum.className='edit';
68    }
69  }
70}
71
72/**
73 * This function generates the actual toolbar buttons with localized text
74 * we use it to avoid creating the toolbar where javascript is not enabled
75 */
76function formatButton(imageFile, speedTip, tagOpen, tagClose, sampleText, accessKey) {
77  speedTip=escapeQuotes(speedTip);
78  tagOpen=escapeQuotes(tagOpen);
79  tagClose=escapeQuotes(tagClose);
80  sampleText=escapeQuotes(sampleText);
81
82  document.write("<a ");
83  if(accessKey){
84    document.write("accesskey=\""+accessKey+"\" ");
85    speedTip = speedTip+' [ALT+'+accessKey.toUpperCase()+']';
86  }
87  document.write("href=\"javascript:insertTags");
88  document.write("('"+tagOpen+"','"+tagClose+"','"+sampleText+"');\">");
89
90  document.write("<img width=\"24\" height=\"24\" src=\""+
91                DOKU_BASE+'lib/images/toolbar/'+imageFile+"\" border=\"0\" alt=\""+
92                speedTip+"\" title=\""+speedTip+"\">");
93  document.write("</a>");
94  return;
95}
96
97/**
98 * This function generates the actual toolbar buttons with localized text
99 * we use it to avoid creating the toolbar where javascript is not enabled
100 */
101function insertButton(imageFile, speedTip, value, accessKey) {
102  speedTip=escapeQuotes(speedTip);
103  value=escapeQuotes(value);
104
105  document.write("<a ");
106  if(accessKey){
107    document.write("accesskey=\""+accessKey+"\" ");
108    speedTip = speedTip+' [ALT+'+accessKey.toUpperCase()+']';
109  }
110  document.write("href=\"javascript:insertAtCarret");
111  document.write("(document.editform.wikitext,'"+value+"');\">");
112
113  document.write("<img width=\"24\" height=\"24\" src=\""+
114                DOKU_BASE+'lib/images/toolbar/'+imageFile+"\" border=\"0\" alt=\""+
115                speedTip+"\" title=\""+speedTip+"\">");
116  document.write("</a>");
117  return;
118}
119
120/**
121 * This adds a button for the MediaSelection Popup
122 */
123function mediaButton(imageFile, speedTip, accessKey, namespace) {
124  speedTip=escapeQuotes(speedTip);
125  document.write("<a ");
126  if(accessKey){
127    document.write("accesskey=\""+accessKey+"\" ");
128  }
129  document.write("href=\"javascript:void(window.open('"+DOKU_BASE+"lib/exe/media.php?ns="+
130                 namespace+"','mediaselect','width=600,height=320,left=70,top=50,scrollbars=yes,resizable=yes'));\">");
131  document.write("<img width=\"24\" height=\"24\" src=\""+
132                 DOKU_BASE+'lib/images/toolbar/'+imageFile+"\" border=\"0\" alt=\""+
133                 speedTip+"\" title=\""+speedTip+"\">");
134  document.write("</a>");
135  return;
136}
137
138/**
139 * apply tagOpen/tagClose to selection in textarea, use sampleText instead
140 * of selection if there is none copied and adapted from phpBB
141 *
142 * @author phpBB development team
143 * @author MediaWiki development team
144 * @author Andreas Gohr <andi@splitbrain.org>
145 * @author Jim Raynor <jim_raynor@web.de>
146 */
147function insertTags(tagOpen, tagClose, sampleText) {
148  var txtarea = document.editform.wikitext;
149  // IE
150  if(document.selection  && !is_gecko) {
151    var theSelection = document.selection.createRange().text;
152    var replaced = true;
153    if(!theSelection){
154      replaced = false;
155      theSelection=sampleText;
156    }
157    txtarea.focus();
158
159    // This has change
160    text = theSelection;
161    if(theSelection.charAt(theSelection.length - 1) == " "){// exclude ending space char, if any
162      theSelection = theSelection.substring(0, theSelection.length - 1);
163      r = document.selection.createRange();
164      r.text = tagOpen + theSelection + tagClose + " ";
165    } else {
166      r = document.selection.createRange();
167      r.text = tagOpen + theSelection + tagClose;
168    }
169    if(!replaced){
170      r.moveStart('character',-text.length-tagClose.length);
171      r.moveEnd('character',-tagClose.length);
172    }
173    r.select();
174  // Mozilla
175  } else if(txtarea.selectionStart || txtarea.selectionStart == '0') {
176    var replaced = false;
177    var startPos = txtarea.selectionStart;
178    var endPos   = txtarea.selectionEnd;
179    if(endPos - startPos) replaced = true;
180    var scrollTop=txtarea.scrollTop;
181    var myText = (txtarea.value).substring(startPos, endPos);
182    if(!myText) { myText=sampleText;}
183    if(myText.charAt(myText.length - 1) == " "){ // exclude ending space char, if any
184      subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " ";
185    } else {
186      subst = tagOpen + myText + tagClose;
187    }
188    txtarea.value = txtarea.value.substring(0, startPos) + subst +
189                    txtarea.value.substring(endPos, txtarea.value.length);
190    txtarea.focus();
191
192    //set new selection
193    if(replaced){
194      var cPos=startPos+(tagOpen.length+myText.length+tagClose.length);
195      txtarea.selectionStart=cPos;
196      txtarea.selectionEnd=cPos;
197    }else{
198      txtarea.selectionStart=startPos+tagOpen.length;
199      txtarea.selectionEnd=startPos+tagOpen.length+myText.length;
200    }
201    txtarea.scrollTop=scrollTop;
202  // All others
203  } else {
204    var copy_alertText=alertText;
205    var re1=new RegExp("\\$1","g");
206    var re2=new RegExp("\\$2","g");
207    copy_alertText=copy_alertText.replace(re1,sampleText);
208    copy_alertText=copy_alertText.replace(re2,tagOpen+sampleText+tagClose);
209    var text;
210    if (sampleText) {
211      text=prompt(copy_alertText);
212    } else {
213      text="";
214    }
215    if(!text) { text=sampleText;}
216    text=tagOpen+text+tagClose;
217    //append to the end
218    txtarea.value += "\n"+text;
219
220    // in Safari this causes scrolling
221    if(!is_safari) {
222      txtarea.focus();
223    }
224
225  }
226  // reposition cursor if possible
227  if (txtarea.createTextRange) txtarea.caretPos = document.selection.createRange().duplicate();
228}
229
230
231/*
232 * Insert the selected filename and close the window
233 *
234 * @see http://www.alexking.org/index.php?content=software/javascript/content.php
235 */
236function mediaSelect(file){
237  insertAtCarret(opener.document.editform.wikitext,'{{'+file+'}}');
238  window.close();
239}
240
241/*
242 * Insert the given value at the current cursor position
243 *
244 * @see http://www.alexking.org/index.php?content=software/javascript/content.php
245 */
246function insertAtCarret(field,value){
247  //IE support
248  if (document.selection) {
249    field.focus();
250    if(opener == null){
251      sel = document.selection.createRange();
252    }else{
253      sel = opener.document.selection.createRange();
254    }
255    sel.text = value;
256  //MOZILLA/NETSCAPE support
257  }else if (field.selectionStart || field.selectionStart == '0') {
258    var startPos  = field.selectionStart;
259    var endPos    = field.selectionEnd;
260    var scrollTop = field.scrollTop;
261    field.value = field.value.substring(0, startPos)
262                  + value
263                  + field.value.substring(endPos, field.value.length);
264
265    field.focus();
266    var cPos=startPos+(value.length);
267    field.selectionStart=cPos;
268    field.selectionEnd=cPos;
269    field.scrollTop=scrollTop;
270  } else {
271    field.value += "\n"+value;
272  }
273  // reposition cursor if possible
274  if (field.createTextRange) field.caretPos = document.selection.createRange().duplicate();
275}
276
277/**
278 * For the upload Dialog. Prefills the wikiname.
279 */
280function suggestWikiname(){
281  var file = document.upload.upload.value;
282
283  file = file.substr(file.lastIndexOf('/')+1);
284  file = file.substr(file.lastIndexOf('\\')+1);
285
286  document.upload.id.value = file;
287}
288
289/**
290 * This prints the switch to toggle the Table of Contents
291 */
292function showTocToggle(showtxt,hidetxt) {
293  if(document.getElementById) {
294		show = '<img src="'+DOKU_BASE+'lib/images/arrow_down.gif" alt="'+showtxt+'">';
295		hide = '<img src="'+DOKU_BASE+'lib/images/arrow_up.gif" alt="'+hidetxt+'">';
296
297    document.writeln('<div class=\'toctoggle\'><a href="javascript:toggleToc()" class="toc">' +
298    '<span id="showlink" style="display:none;">' + show + '</span>' +
299    '<span id="hidelink">' + hide + '</span>'
300    + '</a></div>');
301  }
302}
303
304/**
305 * This toggles the visibility of the Table of Contents
306 */
307function toggleToc() {
308  var toc = document.getElementById('tocinside');
309  var showlink=document.getElementById('showlink');
310  var hidelink=document.getElementById('hidelink');
311  if(toc.style.display == 'none') {
312    toc.style.display = tocWas;
313    hidelink.style.display='';
314    showlink.style.display='none';
315  } else {
316    tocWas = toc.style.display;
317    toc.style.display = 'none';
318    hidelink.style.display='none';
319    showlink.style.display='';
320
321  }
322}
323
324/**
325 * Sizecontrol inspired by TikiWiki. This displays the buttons.
326 */
327function showSizeCtl(){
328  if(document.getElementById) {
329    var textarea = document.getElementById('wikitext');
330    var hgt = getCookie('DokuWikisizeCtl');
331    if(hgt == null){
332      textarea.style.height = '300px';
333    }else{
334      textarea.style.height = hgt;
335    }
336    document.writeln('<a href="javascript:sizeCtl(100)"><img src="'+DOKU_BASE+'lib/images/larger.gif" width="20" height="20" border="0"></a>');
337    document.writeln('<a href="javascript:sizeCtl(-100)"><img src="'+DOKU_BASE+'lib/images/smaller.gif" width="20" height="20" border="0"></a>');
338  }
339}
340
341/**
342 * This sets the vertical size of the editbox
343 */
344function sizeCtl(val){
345  var textarea = document.getElementById('wikitext');
346  var height = parseInt(textarea.style.height.substr(0,textarea.style.height.length-2));
347  height += val;
348  textarea.style.height = height+'px';
349
350  var now = new Date();
351  fixDate(now);
352  now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000); //expire in a year
353  setCookie('DokuWikisizeCtl',textarea.style.height,now);
354}
355
356
357/**
358 * global var used for not saved yet warning
359 */
360var textChanged = false;
361
362function svchk(){
363  if(textChanged){
364    return confirm(notSavedYet);
365  }else{
366    return true;
367  }
368}
369
370/**
371 * global variable for the locktimer
372 */
373var locktimerID;
374
375/**
376 * This starts a timer to remind the user of an expiring lock
377 * Accepts the delay in seconds and a text to display.
378 */
379function init_locktimer(delay,txt){
380  txt = escapeQuotes(txt);
381  locktimerID = self.setTimeout("locktimer('"+txt+"')", delay*1000);
382}
383
384/**
385 * This stops the timer and displays a message about the expiring lock
386 */
387function locktimer(txt){
388  clearTimeout(locktimerID);
389  alert(txt);
390}
391
392/*
393 * This sets a cookie by JavaScript
394 *
395 * @see http://www.webreference.com/js/column8/functions.html
396 */
397function setCookie(name, value, expires, path, domain, secure) {
398  var curCookie = name + "=" + escape(value) +
399      ((expires) ? "; expires=" + expires.toGMTString() : "") +
400      ((path) ? "; path=" + path : "") +
401      ((domain) ? "; domain=" + domain : "") +
402      ((secure) ? "; secure" : "");
403  document.cookie = curCookie;
404}
405
406/*
407 * This reads a cookie by JavaScript
408 *
409 * @see http://www.webreference.com/js/column8/functions.html
410 */
411function getCookie(name) {
412  var dc = document.cookie;
413  var prefix = name + "=";
414  var begin = dc.indexOf("; " + prefix);
415  if (begin == -1) {
416    begin = dc.indexOf(prefix);
417    if (begin != 0) return null;
418  } else
419    begin += 2;
420  var end = document.cookie.indexOf(";", begin);
421  if (end == -1)
422    end = dc.length;
423  return unescape(dc.substring(begin + prefix.length, end));
424}
425
426/*
427 * This is needed for the cookie functions
428 *
429 * @see http://www.webreference.com/js/column8/functions.html
430 */
431function fixDate(date) {
432  var base = new Date(0);
433  var skew = base.getTime();
434  if (skew > 0)
435    date.setTime(date.getTime() - skew);
436}
437
438/*
439 * This enables/disables checkboxes for acl-administration
440 *
441 * @author Frank Schubert <frank@schokilade.de>
442 */
443function checkAclLevel(){
444  if(document.getElementById) {
445    var scope = document.getElementById('acl_scope').value;
446
447    //check for namespace
448    if( (scope.indexOf(":*") > 0) || (scope == "*") ){
449      document.getElementsByName('acl_checkbox[4]')[0].disabled=false;
450      document.getElementsByName('acl_checkbox[8]')[0].disabled=false;
451    }else{
452      document.getElementsByName('acl_checkbox[4]')[0].checked=false;
453      document.getElementsByName('acl_checkbox[8]')[0].checked=false;
454
455      document.getElementsByName('acl_checkbox[4]')[0].disabled=true;
456      document.getElementsByName('acl_checkbox[8]')[0].disabled=true;
457    }
458  }
459}
460