Some enhancements to allmessages filter
[lhc/web/wiklou.git] / skins / common / wikibits.js
1 // Wikipedia JavaScript support functions
2
3 var clientPC = navigator.userAgent.toLowerCase(); // Get client info
4 var is_gecko = ((clientPC.indexOf('gecko')!=-1) && (clientPC.indexOf('spoofer')==-1)
5 && (clientPC.indexOf('khtml') == -1) && (clientPC.indexOf('netscape/7.0')==-1));
6 var is_safari = ((clientPC.indexOf('AppleWebKit')!=-1) && (clientPC.indexOf('spoofer')==-1));
7 var is_khtml = (navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled ));
8 if (clientPC.indexOf('opera') != -1) {
9 var is_opera = true;
10 var is_opera_preseven = (window.opera && !document.childNodes);
11 var is_opera_seven = (window.opera && document.childNodes);
12 }
13
14 // add any onload functions in this hook (please don't hard-code any events in the xhtml source)
15
16 var doneOnloadHook;
17
18 if (!window.onloadFuncts)
19 var onloadFuncts = [];
20
21 function addOnloadHook(hookFunct) {
22 // Allows add-on scripts to add onload functions
23 onloadFuncts[onloadFuncts.length] = hookFunct;
24 }
25
26 function runOnloadHook() {
27 // don't run anything below this for non-dom browsers
28 if (doneOnloadHook || !(document.getElementById && document.getElementsByTagName))
29 return;
30
31 histrowinit();
32 unhidetzbutton();
33 tabbedprefs();
34 akeytt();
35 scrollEditBox();
36
37 // Run any added-on functions
38 for (var i = 0; i < onloadFuncts.length; i++)
39 onloadFuncts[i]();
40
41 doneOnloadHook = true;
42 }
43
44 function hookEvent(hookName, hookFunct) {
45 if (window.addEventListener)
46 addEventListener(hookName, hookFunct, false);
47 else if (window.attachEvent)
48 attachEvent("on" + hookName, hookFunct);
49 }
50
51 hookEvent("load", runOnloadHook);
52
53 // document.write special stylesheet links
54 if (typeof stylepath != 'undefined' && typeof skin != 'undefined') {
55 if (is_opera_preseven) {
56 document.write('<link rel="stylesheet" type="text/css" href="'+stylepath+'/'+skin+'/Opera6Fixes.css">');
57 } else if (is_opera_seven) {
58 document.write('<link rel="stylesheet" type="text/css" href="'+stylepath+'/'+skin+'/Opera7Fixes.css">');
59 } else if (is_khtml) {
60 document.write('<link rel="stylesheet" type="text/css" href="'+stylepath+'/'+skin+'/KHTMLFixes.css">');
61 }
62 }
63 // Un-trap us from framesets
64 if (window.top != window)
65 window.top.location = window.location;
66
67 // for enhanced RecentChanges
68 function toggleVisibility(_levelId, _otherId, _linkId) {
69 var thisLevel = document.getElementById(_levelId);
70 var otherLevel = document.getElementById(_otherId);
71 var linkLevel = document.getElementById(_linkId);
72 if (thisLevel.style.display == 'none') {
73 thisLevel.style.display = 'block';
74 otherLevel.style.display = 'none';
75 linkLevel.style.display = 'inline';
76 } else {
77 thisLevel.style.display = 'none';
78 otherLevel.style.display = 'inline';
79 linkLevel.style.display = 'none';
80 }
81 }
82
83 // page history stuff
84 // attach event handlers to the input elements on history page
85 function histrowinit() {
86 hf = document.getElementById('pagehistory');
87 if (!hf)
88 return;
89 lis = hf.getElementsByTagName('li');
90 for (i = 0; i < lis.length; i++) {
91 inputs = lis[i].getElementsByTagName('input');
92 if (inputs[0] && inputs[1]) {
93 inputs[0].onclick = diffcheck;
94 inputs[1].onclick = diffcheck;
95 }
96 }
97 diffcheck();
98 }
99
100 // check selection and tweak visibility/class onclick
101 function diffcheck() {
102 var dli = false; // the li where the diff radio is checked
103 var oli = false; // the li where the oldid radio is checked
104 hf = document.getElementById('pagehistory');
105 if (!hf)
106 return;
107 lis = hf.getElementsByTagName('li');
108 for (i=0;i<lis.length;i++) {
109 inputs = lis[i].getElementsByTagName('input');
110 if (inputs[1] && inputs[0]) {
111 if (inputs[1].checked || inputs[0].checked) { // this row has a checked radio button
112 if (inputs[1].checked && inputs[0].checked && inputs[0].value == inputs[1].value)
113 return false;
114 if (oli) { // it's the second checked radio
115 if (inputs[1].checked) {
116 oli.className = "selected";
117 return false
118 }
119 } else if (inputs[0].checked) {
120 return false;
121 }
122 if (inputs[0].checked)
123 dli = lis[i];
124 if (!oli)
125 inputs[0].style.visibility = 'hidden';
126 if (dli)
127 inputs[1].style.visibility = 'hidden';
128 lis[i].className = "selected";
129 oli = lis[i];
130 } else { // no radio is checked in this row
131 if (!oli)
132 inputs[0].style.visibility = 'hidden';
133 else
134 inputs[0].style.visibility = 'visible';
135 if (dli)
136 inputs[1].style.visibility = 'hidden';
137 else
138 inputs[1].style.visibility = 'visible';
139 lis[i].className = "";
140 }
141 }
142 }
143 }
144
145 // generate toc from prefs form, fold sections
146 // XXX: needs testing on IE/Mac and safari
147 // more comments to follow
148 function tabbedprefs() {
149 var prefform = document.getElementById('preferences');
150 if (!prefform || !document.createElement)
151 return;
152 if (prefform.nodeName.toLowerCase() == 'a')
153 return; // Occasional IE problem
154 prefform.className = prefform.className + 'jsprefs';
155 var sections = new Array();
156 children = prefform.childNodes;
157 var seci = 0;
158 for (i = 0; i < children.length; i++) {
159 if (children[i].nodeName.toLowerCase() == 'fieldset') {
160 children[i].id = 'prefsection-' + seci;
161 children[i].className = 'prefsection';
162 if (is_opera || is_khtml)
163 children[i].className = 'prefsection operaprefsection';
164 legends = children[i].getElementsByTagName('legend');
165 sections[seci] = new Object();
166 legends[0].className = 'mainLegend';
167 if (legends[0] && legends[0].firstChild.nodeValue)
168 sections[seci].text = legends[0].firstChild.nodeValue;
169 else
170 sections[seci].text = '# ' + seci;
171 sections[seci].secid = children[i].id;
172 seci++;
173 if (sections.length != 1)
174 children[i].style.display = 'none';
175 else
176 var selectedid = children[i].id;
177 }
178 }
179 var toc = document.createElement('ul');
180 toc.id = 'preftoc';
181 toc.selectedid = selectedid;
182 for (i = 0; i < sections.length; i++) {
183 var li = document.createElement('li');
184 if (i == 0)
185 li.className = 'selected';
186 var a = document.createElement('a');
187 a.href = '#' + sections[i].secid;
188 a.onmousedown = a.onclick = uncoversection;
189 a.appendChild(document.createTextNode(sections[i].text));
190 a.secid = sections[i].secid;
191 li.appendChild(a);
192 toc.appendChild(li);
193 }
194 prefform.parentNode.insertBefore(toc, prefform.parentNode.childNodes[0]);
195 document.getElementById('prefsubmit').id = 'prefcontrol';
196 }
197
198 function uncoversection() {
199 oldsecid = this.parentNode.parentNode.selectedid;
200 newsec = document.getElementById(this.secid);
201 if (oldsecid != this.secid) {
202 ul = document.getElementById('preftoc');
203 document.getElementById(oldsecid).style.display = 'none';
204 newsec.style.display = 'block';
205 ul.selectedid = this.secid;
206 lis = ul.getElementsByTagName('li');
207 for (i = 0; i< lis.length; i++) {
208 lis[i].className = '';
209 }
210 this.parentNode.className = 'selected';
211 }
212 return false;
213 }
214
215 // Timezone stuff
216 // tz in format [+-]HHMM
217 function checkTimezone(tz, msg) {
218 var localclock = new Date();
219 // returns negative offset from GMT in minutes
220 var tzRaw = localclock.getTimezoneOffset();
221 var tzHour = Math.floor( Math.abs(tzRaw) / 60);
222 var tzMin = Math.abs(tzRaw) % 60;
223 var tzString = ((tzRaw >= 0) ? "-" : "+") + ((tzHour < 10) ? "0" : "") + tzHour + ((tzMin < 10) ? "0" : "") + tzMin;
224 if (tz != tzString) {
225 var junk = msg.split('$1');
226 document.write(junk[0] + "UTC" + tzString + junk[1]);
227 }
228 }
229
230 function unhidetzbutton() {
231 tzb = document.getElementById('guesstimezonebutton')
232 if (tzb)
233 tzb.style.display = 'inline';
234 }
235
236 // in [-]HH:MM format...
237 // won't yet work with non-even tzs
238 function fetchTimezone() {
239 // FIXME: work around Safari bug
240 var localclock = new Date();
241 // returns negative offset from GMT in minutes
242 var tzRaw = localclock.getTimezoneOffset();
243 var tzHour = Math.floor( Math.abs(tzRaw) / 60);
244 var tzMin = Math.abs(tzRaw) % 60;
245 var tzString = ((tzRaw >= 0) ? "-" : "") + ((tzHour < 10) ? "0" : "") + tzHour +
246 ":" + ((tzMin < 10) ? "0" : "") + tzMin;
247 return tzString;
248 }
249
250 function guessTimezone(box) {
251 document.getElementsByName("wpHourDiff")[0].value = fetchTimezone();
252 }
253
254 function showTocToggle() {
255 if (document.createTextNode) {
256 // Uses DOM calls to avoid document.write + XHTML issues
257
258 var linkHolder = document.getElementById('toctitle')
259 if (!linkHolder)
260 return;
261
262 var outerSpan = document.createElement('span');
263 outerSpan.className = 'toctoggle';
264
265 var toggleLink = document.createElement('a');
266 toggleLink.id = 'togglelink';
267 toggleLink.className = 'internal';
268 toggleLink.href = 'javascript:toggleToc()';
269 toggleLink.appendChild(document.createTextNode(tocHideText));
270
271 outerSpan.appendChild(document.createTextNode('['));
272 outerSpan.appendChild(toggleLink);
273 outerSpan.appendChild(document.createTextNode(']'));
274
275 linkHolder.appendChild(document.createTextNode(' '));
276 linkHolder.appendChild(outerSpan);
277
278 var cookiePos = document.cookie.indexOf("hidetoc=");
279 if (cookiePos > -1 && document.cookie.charAt(cookiePos + 8) == 1)
280 toggleToc();
281 }
282 }
283
284 function changeText(el, newText) {
285 // Safari work around
286 if (el.innerText)
287 el.innerText = newText;
288 else if (el.firstChild && el.firstChild.nodeValue)
289 el.firstChild.nodeValue = newText;
290 }
291
292 function toggleToc() {
293 var toc = document.getElementById('toc').getElementsByTagName('ul')[0];
294 var toggleLink = document.getElementById('togglelink')
295
296 if (toc && toggleLink && toc.style.display == 'none') {
297 changeText(toggleLink, tocHideText);
298 toc.style.display = 'block';
299 document.cookie = "hidetoc=0";
300 } else {
301 changeText(toggleLink, tocShowText);
302 toc.style.display = 'none';
303 document.cookie = "hidetoc=1";
304 }
305 }
306
307 // this function generates the actual toolbar buttons with localized text
308 // we use it to avoid creating the toolbar where javascript is not enabled
309 function addButton(imageFile, speedTip, tagOpen, tagClose, sampleText) {
310 // Don't generate buttons for browsers which don't fully
311 // support it.
312 if (!document.selection && !is_gecko) {
313 return false;
314 }
315 imageFile = escapeQuotesHTML(imageFile);
316 speedTip = escapeQuotesHTML(speedTip);
317 tagOpen = escapeQuotes(tagOpen);
318 tagClose = escapeQuotes(tagClose);
319 sampleText = escapeQuotes(sampleText);
320 var mouseOver = "";
321
322 document.write("<a href=\"javascript:insertTags");
323 document.write("('"+tagOpen+"','"+tagClose+"','"+sampleText+"');\">");
324 document.write("<img width=\"23\" height=\"22\" src=\""+imageFile+"\" border=\"0\" alt=\""+speedTip+"\" title=\""+speedTip+"\""+mouseOver+">");
325 document.write("</a>");
326 return;
327 }
328
329 function escapeQuotes(text) {
330 var re = new RegExp("'","g");
331 text = text.replace(re,"\\'");
332 re = new RegExp("\\n","g");
333 text = text.replace(re,"\\n");
334 return escapeQuotesHTML(text);
335 }
336
337 function escapeQuotesHTML(text) {
338 var re = new RegExp('&',"g");
339 text = text.replace(re,"&amp;");
340 var re = new RegExp('"',"g");
341 text = text.replace(re,"&quot;");
342 var re = new RegExp('<',"g");
343 text = text.replace(re,"&lt;");
344 var re = new RegExp('>',"g");
345 text = text.replace(re,"&gt;");
346 return text;
347 }
348
349 // apply tagOpen/tagClose to selection in textarea,
350 // use sampleText instead of selection if there is none
351 // copied and adapted from phpBB
352 function insertTags(tagOpen, tagClose, sampleText) {
353 if (document.editform)
354 var txtarea = document.editform.wpTextbox1;
355 else {
356 // some alternate form? take the first one we can find
357 var areas = document.getElementsByTagName('textarea');
358 var txtarea = areas[0];
359 }
360
361 // IE
362 if (document.selection && !is_gecko) {
363 var theSelection = document.selection.createRange().text;
364 if (!theSelection)
365 theSelection=sampleText;
366 txtarea.focus();
367 if (theSelection.charAt(theSelection.length - 1) == " ") { // exclude ending space char, if any
368 theSelection = theSelection.substring(0, theSelection.length - 1);
369 document.selection.createRange().text = tagOpen + theSelection + tagClose + " ";
370 } else {
371 document.selection.createRange().text = tagOpen + theSelection + tagClose;
372 }
373
374 // Mozilla
375 } else if(txtarea.selectionStart || txtarea.selectionStart == '0') {
376 var replaced = false;
377 var startPos = txtarea.selectionStart;
378 var endPos = txtarea.selectionEnd;
379 if (endPos-startPos)
380 replaced = true;
381 var scrollTop = txtarea.scrollTop;
382 var myText = (txtarea.value).substring(startPos, endPos);
383 if (!myText)
384 myText=sampleText;
385 if (myText.charAt(myText.length - 1) == " ") { // exclude ending space char, if any
386 subst = tagOpen + myText.substring(0, (myText.length - 1)) + tagClose + " ";
387 } else {
388 subst = tagOpen + myText + tagClose;
389 }
390 txtarea.value = txtarea.value.substring(0, startPos) + subst +
391 txtarea.value.substring(endPos, txtarea.value.length);
392 txtarea.focus();
393 //set new selection
394 if (replaced) {
395 var cPos = startPos+(tagOpen.length+myText.length+tagClose.length);
396 txtarea.selectionStart = cPos;
397 txtarea.selectionEnd = cPos;
398 } else {
399 txtarea.selectionStart = startPos+tagOpen.length;
400 txtarea.selectionEnd = startPos+tagOpen.length+myText.length;
401 }
402 txtarea.scrollTop = scrollTop;
403
404 // All other browsers get no toolbar.
405 // There was previously support for a crippled "help"
406 // bar, but that caused more problems than it solved.
407 }
408 // reposition cursor if possible
409 if (txtarea.createTextRange)
410 txtarea.caretPos = document.selection.createRange().duplicate();
411 }
412
413 function akeytt() {
414 if (typeof ta == "undefined" || !ta)
415 return;
416 var pref = 'alt-';
417 if (is_safari || navigator.userAgent.toLowerCase().indexOf('mac') + 1
418 || navigator.userAgent.toLowerCase().indexOf('konqueror') + 1 )
419 pref = 'control-';
420 if (is_opera)
421 pref = 'shift-esc-';
422
423 for (var id in ta) {
424 var n = document.getElementById(id);
425 if (n) {
426 var a = null;
427 var ak = '';
428 // Are we putting accesskey in it
429 if (ta[id][0].length > 0) {
430 // Is this object a object? If not assume it's the next child.
431
432 if (n.nodeName.toLowerCase() == "a") {
433 a = n;
434 } else {
435 a = n.childNodes[0];
436 }
437
438 if (a) {
439 a.accessKey = ta[id][0];
440 ak = ' ['+pref+ta[id][0]+']';
441 }
442 } else {
443 // We don't care what type the object is when assigning tooltip
444 a = n;
445 ak = '';
446 }
447
448 if (a) {
449 a.title = ta[id][1]+ak;
450 }
451 }
452 }
453 }
454
455 function setupRightClickEdit() {
456 if (document.getElementsByTagName) {
457 var divs = document.getElementsByTagName('div');
458 for (var i = 0; i < divs.length; i++) {
459 var el = divs[i];
460 if(el.className == 'editsection') {
461 addRightClickEditHandler(el);
462 }
463 }
464 }
465 }
466
467 function addRightClickEditHandler(el) {
468 for (var i = 0; i < el.childNodes.length; i++) {
469 var link = el.childNodes[i];
470 if (link.nodeType == 1 && link.nodeName.toLowerCase() == 'a') {
471 var editHref = link.getAttribute('href');
472
473 // find the following a
474 var next = el.nextSibling;
475 while (next.nodeType != 1)
476 next = next.nextSibling;
477
478 // find the following header
479 next = next.nextSibling;
480 while (next.nodeType != 1)
481 next = next.nextSibling;
482
483 if (next && next.nodeType == 1 &&
484 next.nodeName.match(/^[Hh][1-6]$/)) {
485 next.oncontextmenu = function() {
486 document.location = editHref;
487 return false;
488 }
489 }
490 }
491 }
492 }
493
494 function fillDestFilename() {
495 if (!document.getElementById)
496 return;
497 var path = document.getElementById('wpUploadFile').value;
498 // Find trailing part
499 var slash = path.lastIndexOf('/');
500 var backslash = path.lastIndexOf('\\');
501 var fname;
502 if (slash == -1 && backslash == -1) {
503 fname = path;
504 } else if (slash > backslash) {
505 fname = path.substring(slash+1, 10000);
506 } else {
507 fname = path.substring(backslash+1, 10000);
508 }
509
510 // Capitalise first letter and replace spaces by underscores
511 fname = fname.charAt(0).toUpperCase().concat(fname.substring(1,10000)).replace(/ /g, '_');
512
513 // Output result
514 var destFile = document.getElementById('wpDestFile');
515 if (destFile)
516 destFile.value = fname;
517 }
518
519
520 function considerChangingExpiryFocus() {
521 if (!document.getElementById)
522 return;
523 var drop = document.getElementById('wpBlockExpiry');
524 if (!drop)
525 return;
526 var field = document.getElementById('wpBlockOther');
527 if (!field)
528 return;
529 var opt = drop.value;
530 if (opt == 'other')
531 field.style.display = '';
532 else
533 field.style.display = 'none';
534 }
535
536 function scrollEditBox() {
537 var editBoxEl = document.getElementById("wpTextbox1");
538 var scrollTopEl = document.getElementById("wpScrolltop");
539 var editFormEl = document.getElementById("editform");
540
541 if (editBoxEl && scrollTopEl) {
542 if (scrollTopEl.value) editBoxEl.scrollTop = scrollTopEl.value;
543 editFormEl.onsubmit = function() {
544 document.getElementById("wpScrolltop").value = document.getElementById("wpTextbox1").scrollTop;
545 }
546 }
547 }
548
549 hookEvent("load", scrollEditBox);
550
551 function allmessagesfilter() {
552 text = document.getElementById('allmessagesinput').value;
553 k = document.getElementById('allmessagestable');
554 if (!k) { return;}
555
556 var items = k.getElementsByTagName('span');
557
558 if ( text.length > allmessages_prev.length ) {
559 for (var i = items.length-1, j = 0; i >= 0; i--) {
560 j = allmessagesforeach(items, i, j);
561 }
562 } else {
563 for (var i = 0, j = 0; i < items.length; i++) {
564 j = allmessagesforeach(items, i, j);
565 }
566 }
567 allmessages_prev = text;
568 }
569
570 function allmessagesforeach(items, i, j) {
571 var hItem = items[i].getAttribute('id');
572 if (hItem.substring(0,17) == 'sp-allmessages-i-') {
573 if (items[i].firstChild && items[i].firstChild.nodeName == '#text' && items[i].firstChild.nodeValue.indexOf(text) != -1) {
574 var itemA = document.getElementById( hItem.replace('i', 'r1') );
575 var itemB = document.getElementById( hItem.replace('i', 'r2') );
576 if ( itemA.style.display != '' ) {
577 var s = "allmessageshider(\"" + hItem.replace('i', 'r1') + "\", \"" + hItem.replace('i', 'r2') + "\", '')";
578 var k = window.setTimeout(s,j++*5);
579 }
580 } else {
581 var itemA = document.getElementById( hItem.replace('i', 'r1') );
582 var itemB = document.getElementById( hItem.replace('i', 'r2') );
583 if ( itemA.style.display != 'none' ) {
584 var s = "allmessageshider(\"" + hItem.replace('i', 'r1') + "\", \"" + hItem.replace('i', 'r2') + "\", 'none')";
585 var k = window.setTimeout(s,j++*5);
586 }
587 }
588 }
589 return j;
590 }
591
592
593 function allmessageshider(idA, idB, cstyle) {
594 var itemA = document.getElementById( idA );
595 var itemB = document.getElementById( idB );
596 if (itemA) { itemA.style.display = cstyle; }
597 if (itemB) { itemB.style.display = cstyle; }
598 }
599
600 function allmessagesmodified() {
601 allmessages_modified = !allmessages_modified;
602 k = document.getElementById('allmessagestable');
603 if (!k) { return;}
604 var items = k.getElementsByTagName('tr');
605 for (var i = 0, j = 0; i< items.length; i++) {
606 if (!allmessages_modified ) {
607 if ( items[i].style.display != '' ) {
608 var s = "allmessageshider(\"" + items[i].getAttribute('id') + "\", null, '')";
609 var k = window.setTimeout(s,j++*5);
610 }
611 } else if (items[i].getAttribute('class') == 'def' && allmessages_modified) {
612 if ( items[i].style.display != 'none' ) {
613 var s = "allmessageshider(\"" + items[i].getAttribute('id') + "\", null, 'none')";
614 var k = window.setTimeout(s,j++*5);
615 }
616 }
617 }
618 }
619
620 function allmessagesshow() {
621 k = document.getElementById('allmessagesfilter');
622 if (k) { k.style.display = ''; }
623
624 allmessages_prev = '';
625 allmessages_modified = false;
626 }
627
628 hookEvent("load", allmessagesshow);