comparison slidy.js @ 0:dacfe6e2d9e7 default tip

hg init
author Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp>
date Sun, 11 Jul 2010 23:08:46 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:dacfe6e2d9e7
1 /* slidy.js
2
3 Copyright (c) 2005-2009 W3C (MIT, ERCIM, Keio), All Rights Reserved.
4 W3C liability, trademark, document use and software licensing
5 rules apply, see:
6
7 http://www.w3.org/Consortium/Legal/copyright-documents
8 http://www.w3.org/Consortium/Legal/copyright-software
9 */
10
11 var ns_pos = (typeof window.pageYOffset!='undefined');
12 var khtml = ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false);
13 var opera = ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false);
14 var ie = (typeof document.all != "undefined" && !opera);
15 var ie7 = (!ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1);
16 var ie8 = (!ns_pos && navigator.userAgent.indexOf("MSIE 8") != -1);
17 var slidy_started = false;
18
19 if (ie && !ie8)
20 document.write("<iframe id='historyFrame' src='javascript:\"<html"+"></"+"html>\"' height='1' width='1' style='position:absolute;left:-800px'></iframe>");
21
22 // IE only event handlers to ensure all slides are printed
23 // I don't yet know how to emulate these for other browsers
24 if (typeof beforePrint != 'undefined')
25 {
26 window.onbeforeprint = beforePrint;
27 window.onafterprint = afterPrint;
28 }
29
30 // to avoid a clash with other scripts or onload attribute on <body>
31 // we use something smarter than window.onload
32 //window.onload = startup;
33
34
35 if (ie)
36 setTimeout(ieSlidyInit, 100);
37 else if (document.addEventListener)
38 document.addEventListener("DOMContentLoaded", startup, false);
39
40 function ieSlidyInit()
41 {
42 if (//document.readyState == "interactive" ||
43 document.readyState == "complete" ||
44 document.readyState == "loaded")
45 {
46 startup();
47 }
48 else
49 {
50 setTimeout(ieSlidyInit, 100);
51 }
52 }
53
54 setTimeout(hideSlides, 50);
55
56 function hideSlides()
57 {
58 if (document.body)
59 document.body.style.visibility = "hidden";
60 else
61 setTimeout(hideSlides, 50);
62 }
63
64 var slidenum = 0; // integer slide count: 0, 1, 2, ...
65 var slides; // set to array of slide div's
66 var slideNumElement; // element containing slide number
67 var notes; // set to array of handout div's
68 var backgrounds; // set to array of background div's
69 var toolbar; // element containing toolbar
70 var title; // document title
71 var lastShown = null; // last incrementally shown item
72 var eos = null; // span element for end of slide indicator
73 var toc = null; // table of contents
74 var outline = null; // outline element with the focus
75 var selectedTextLen; // length of drag selection on document
76
77 var viewAll = 0; // 1 to view all slides + handouts
78 var wantToolbar = 1; // 0 if toolbar isn't wanted
79 var mouseClickEnabled = true; // enables left click for next slide
80 var scrollhack = 0; // IE work around for position: fixed
81 var key_wanted = false;
82
83 var helpAnchor; // used for keyboard focus hack in showToolbar()
84 var helpPage = "http://www.w3.org/Talks/Tools/Slidy/help.html";
85 var helpText = "Navigate with mouse click, space bar, Cursor Left/Right, " +
86 "or Pg Up and Pg Dn. Use S and B to change font size.";
87
88 var sizeIndex = 0;
89 var sizeAdjustment = 0;
90 var sizes = new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
91 "22pt", "24pt", "26pt", "28pt", "30pt", "32pt");
92 var okayForIncremental = incrementalElementList();
93
94 // needed for efficient resizing
95 var lastWidth = 0;
96 var lastHeight = 0;
97
98 // Needed for cross browser support for relative width/height on
99 // object elements. The work around is to save width/height attributes
100 // and then to recompute absolute width/height dimensions on resizing
101 var objects;
102
103 // updated to language specified by html file
104 var lang = "en";
105
106 //var localize = {};
107
108 // for each language there is an associative array
109 var strings_es = {
110 "slide":"pág.",
111 "help?":"Ayuda",
112 "contents?":"Índice",
113 "table of contents":"tabla de contenidos",
114 "Table of Contents":"Tabla de Contenidos",
115 "restart presentation":"Reiniciar presentación",
116 "restart?":"Inicio"
117 };
118
119 strings_es[helpText] =
120 "Utilice el ratón, barra espaciadora, teclas Izda/Dcha, " +
121 "o Re pág y Av pág. Use S y B para cambiar el tamaño de fuente.";
122
123 var strings_ca = {
124 "slide":"pàg..",
125 "help?":"Ajuda",
126 "contents?":"Índex",
127 "table of contents":"taula de continguts",
128 "Table of Contents":"Taula de Continguts",
129 "restart presentation":"Reiniciar presentació",
130 "restart?":"Inici"
131 };
132
133 strings_ca[helpText] =
134 "Utilitzi el ratolí, barra espaiadora, tecles Esq./Dta. " +
135 "o Re pàg y Av pàg. Usi S i B per canviar grandària de font.";
136
137 var strings_nl = {
138 "slide":"pagina",
139 "help?":"Help?",
140 "contents?":"Inhoud?",
141 "table of contents":"inhoudsopgave",
142 "Table of Contents":"Inhoudsopgave",
143 "restart presentation":"herstart presentatie",
144 "restart?":"Herstart?"
145 };
146
147 strings_nl[helpText] =
148 "Navigeer d.m.v. het muis, spatiebar, Links/Rechts toetsen, " +
149 "of PgUp en PgDn. Gebruik S en B om de karaktergrootte te veranderen.";
150
151 var strings_de = {
152 "slide":"Seite",
153 "help?":"Hilfe",
154 "contents?":"Übersicht",
155 "table of contents":"Inhaltsverzeichnis",
156 "Table of Contents":"Inhaltsverzeichnis",
157 "restart presentation":"Präsentation neu starten",
158 "restart?":"Neustart"
159 };
160
161 strings_de[helpText] =
162 "Benutzen Sie die Maus, Leerschlag, die Cursortasten links/rechts oder " +
163 "Page up/Page Down zum Wechseln der Seiten und S und B für die Schriftgrösse.";
164
165 var strings_pl = {
166 "slide":"slajd",
167 "help?":"pomoc?",
168 "contents?":"spis treści?",
169 "table of contents":"spis treści",
170 "Table of Contents":"Spis Treści",
171 "restart presentation":"Restartuj prezentację",
172 "restart?":"restart?"
173 };
174
175 strings_pl[helpText] =
176 "Zmieniaj slajdy klikając myszą, naciskając spację, strzałki lewo/prawo" +
177 "lub PgUp / PgDn. Użyj klawiszy S i B, aby zmienić rozmiar czczionki.";
178
179 var strings_fr = {
180 "slide":"page",
181 "help?":"Aide",
182 "contents?":"Index",
183 "table of contents":"table des matières",
184 "Table of Contents":"Table des matières",
185 "restart presentation":"Recommencer l'exposé",
186 "restart?":"Début"
187 };
188
189 strings_fr[helpText] =
190 "Naviguez avec la souris, la barre d'espace, les flèches " +
191 "gauche/droite ou les touches Pg Up, Pg Dn. Utilisez " +
192 "les touches S et B pour modifier la taille de la police.";
193
194 var strings_hu = {
195 "slide":"oldal",
196 "help?":"segítség",
197 "contents?":"tartalom",
198 "table of contents":"tartalomjegyzék",
199 "Table of Contents":"Tartalomjegyzék",
200 "restart presentation":"bemutató újraindítása",
201 "restart?":"újraindítás"
202 };
203
204 strings_hu[helpText] =
205 "Az oldalak közti lépkedéshez kattintson az egérrel, vagy " +
206 "használja a szóköz, a bal, vagy a jobb nyíl, illetve a Page Down, " +
207 "Page Up billentyűket. Az S és a B billentyűkkel változtathatja " +
208 "a szöveg méretét.";
209
210 var strings_it = {
211 "slide":"pag.",
212 "help?":"Aiuto",
213 "contents?":"Indice",
214 "table of contents":"indice",
215 "Table of Contents":"Indice",
216 "restart presentation":"Ricominciare la presentazione",
217 "restart?":"Inizio"
218 };
219
220 strings_it[helpText] =
221 "Navigare con mouse, barra spazio, frecce sinistra/destra o " +
222 "PgUp e PgDn. Usare S e B per cambiare la dimensione dei caratteri.";
223
224 var strings_el = {
225 "slide":"σελίδα",
226 "help?":"βοήθεια;",
227 "contents?":"περιεχόμενα;",
228 "table of contents":"πίνακας περιεχομένων",
229 "Table of Contents":"Πίνακας Περιεχομένων",
230 "restart presentation":"επανεκκίνηση παρουσίασης",
231 "restart?":"επανεκκίνηση;"
232 };
233
234 strings_el[helpText] =
235 "Πλοηγηθείτε με το κλίκ του ποντικιού, το space, τα βέλη αριστερά/δεξιά, " +
236 "ή Page Up και Page Down. Χρησιμοποιήστε τα πλήκτρα S και B για να αλλάξετε " +
237 "το μέγεθος της γραμματοσειράς.";
238
239 var strings_ja = {
240 "slide":"スライド",
241 "help?":"ヘルプ",
242 "contents?":"目次",
243 "table of contents":"目次を表示",
244 "Table of Contents":"目次",
245 "restart presentation":"最初から再生",
246 "restart?":"最初から"
247 };
248
249 strings_ja[helpText] =
250 "マウス左クリック ・ スペース ・ 左右キー " +
251 "または Page Up ・ Page Downで操作, S ・ Bでフォントサイズ変更";
252
253 var strings_zh = {
254 "slide":"幻灯片",
255 "help?":"帮助?",
256 "contents?":"内容?",
257 "table of contents":"目录",
258 "Table of Contents":"目录",
259 "restart presentation":"重新启动展示",
260 "restart?":"重新启动?"
261 };
262
263 strings_zh[helpText] =
264 "用鼠标点击, 空格条, 左右箭头, Pg Up 和 Pg Dn 导航. " +
265 "用 S, B 改变字体大小.";
266
267 var strings_ru = {
268 "slide":"слайд",
269 "help?":"помощь?",
270 "contents?":"содержание?",
271 "table of contents":"оглавление",
272 "Table of Contents":"Оглавление",
273 "restart presentation":"перезапустить презентацию",
274 "restart?":"перезапуск?"
275 };
276
277 strings_ru[helpText] =
278 "Перемещайтесь кликая мышкой, используя клавишу пробел, стрелки" +
279 "влево/вправо или Pg Up и Pg Dn. Клавиши S и B меняют размер шрифта.";
280
281 var strings_sv = {
282 "slide":"sida",
283 "help?":"hjälp",
284 "contents?":"innehåll",
285 "table of contents":"innehållsförteckning",
286 "Table of Contents":"Innehållsförteckning",
287 "restart presentation":"visa presentationen från början",
288 "restart?":"börja om"
289 };
290
291 strings_sv[helpText] =
292 "Bläddra med ett klick med vänstra musknappen, mellanslagstangenten, " +
293 "vänster- och högerpiltangenterna eller tangenterna Pg Up, Pg Dn. " +
294 "Använd tangenterna S och B för att ändra textens storlek.";
295
296 // each such language array is declared in the localize array
297 // used indirectly as in help.innerHTML = "help".localize();
298 var localize = {
299 "es":strings_es,
300 "ca":strings_ca,
301 "nl":strings_nl,
302 "de":strings_de,
303 "pl":strings_pl,
304 "fr":strings_fr,
305 "hu":strings_hu,
306 "it":strings_it,
307 "el":strings_el,
308 "jp":strings_ja,
309 "zh":strings_zh,
310 "ru":strings_ru,
311 "sv":strings_sv
312 };
313
314 /* general initialization */
315 function startup()
316 {
317 if (slidy_started)
318 {
319 alert("already started");
320 return;
321 }
322 slidy_started = true;
323
324 // find human language from html element
325 // for use in localizing strings
326 lang = document.body.parentNode.getAttribute("lang");
327
328 if (!lang)
329 lang = document.body.parentNode.getAttribute("xml:lang");
330
331 if (!lang)
332 lang = "en";
333
334 document.body.style.visibility = "visible";
335 title = document.title;
336 toolbar = addToolbar();
337 wrapImplicitSlides();
338 slides = collectSlides();
339 notes = collectNotes();
340 objects = document.body.getElementsByTagName("object");
341 backgrounds = collectBackgrounds();
342 patchAnchors();
343
344 slidenum = findSlideNumber(location.href);
345 window.offscreenbuffering = true;
346 sizeAdjustment = findSizeAdjust();
347 hideImageToolbar(); // suppress IE image toolbar popup
348 initOutliner(); // activate fold/unfold support
349
350 if (slides.length > 0)
351 {
352 var slide = slides[slidenum];
353 slide.style.position = "absolute";
354
355 if (slidenum > 0)
356 {
357 setVisibilityAllIncremental("visible");
358 lastShown = previousIncrementalItem(null);
359 setEosStatus(true);
360 }
361 else
362 {
363 lastShown = null;
364 setVisibilityAllIncremental("hidden");
365 setEosStatus(!nextIncrementalItem(lastShown));
366 }
367
368 setLocation();
369 }
370
371 toc = tableOfContents();
372 hideTableOfContents();
373
374 // bind event handlers
375 document.onclick = mouseButtonClick;
376 document.onmouseup = mouseButtonUp;
377 document.onkeydown = keyDown;
378 if (opera)
379 document.onkeypress = keyPress;
380 window.onresize = resized;
381 window.onscroll = scrolled;
382 window.onunload = unloaded;
383 singleSlideView();
384
385
386 setLocation();
387 resized();
388
389 if (ie7)
390 setTimeout("ieHack()", 100);
391
392 showToolbar();
393 setInterval("checkLocation()", 200); // for back button detection
394 }
395
396 // add localize method to all strings for use
397 // as in help.innerHTML = "help".localize();
398 String.prototype.localize = function()
399 {
400 if (this == "")
401 return this;
402
403 // try full language code, e.g. en-US
404 var s, lookup = localize[lang];
405
406 if (lookup)
407 {
408 s = lookup[this];
409
410 if (s)
411 return s;
412 }
413
414 // try en if undefined for en-US
415 var lg = lang.split("-");
416
417 if (lg.length > 1)
418 {
419 lookup = localize[lg[0]];
420
421 if (lookup)
422 {
423 s = lookup[this];
424
425 if (s)
426 return s;
427 }
428 }
429
430 // otherwise string as is
431 return this;
432 }
433
434 // suppress IE's image toolbar pop up
435 function hideImageToolbar()
436 {
437 if (!ns_pos)
438 {
439 var images = document.getElementsByTagName("IMG");
440
441 for (var i = 0; i < images.length; ++i)
442 images[i].setAttribute("galleryimg", "no");
443 }
444 }
445
446 // hack to persuade IE to compute correct document height
447 // as needed for simulating fixed positioning of toolbar
448 function ieHack()
449 {
450 window.resizeBy(0,-1);
451 window.resizeBy(0, 1);
452 }
453
454 function unloaded(e)
455 {
456 //alert("unloaded");
457 }
458
459 // Firefox reload SVG bug work around
460 function reload(e)
461 {
462 if (!e)
463 var e = window.event;
464
465 hideBackgrounds();
466 setTimeout("document.reload();", 100);
467
468 stopPropagation(e);
469 e.cancel = true;
470 e.returnValue = false;
471
472 return false;
473 }
474
475 // Safari and Konqueror don't yet support getComputedStyle()
476 // and they always reload page when location.href is updated
477 function isKHTML()
478 {
479 var agent = navigator.userAgent;
480 return (agent.indexOf("KHTML") >= 0 ? true : false);
481 }
482
483 function resized()
484 {
485 var width = 0;
486
487 if ( typeof( window.innerWidth ) == 'number' )
488 width = window.innerWidth; // Non IE browser
489 else if (document.documentElement && document.documentElement.clientWidth)
490 width = document.documentElement.clientWidth; // IE6
491 else if (document.body && document.body.clientWidth)
492 width = document.body.clientWidth; // IE4
493
494 var height = 0;
495
496 if ( typeof( window.innerHeight ) == 'number' )
497 height = window.innerHeight; // Non IE browser
498 else if (document.documentElement && document.documentElement.clientHeight)
499 height = document.documentElement.clientHeight; // IE6
500 else if (document.body && document.body.clientHeight)
501 height = document.body.clientHeight; // IE4
502
503 if (height && (width/height > 1.05*1024/768))
504 {
505 width = height * 1024.0/768;
506 }
507
508 // IE fires onresize even when only font size is changed!
509 // so we do a check to avoid blocking < and > actions
510 if (width != lastWidth || height != lastHeight)
511 {
512 if (width >= 1100)
513 sizeIndex = 5; // 4
514 else if (width >= 1000)
515 sizeIndex = 4; // 3
516 else if (width >= 800)
517 sizeIndex = 3; // 2
518 else if (width >= 600)
519 sizeIndex = 2; // 1
520 else if (width)
521 sizeIndex = 0;
522
523 // add in font size adjustment from meta element e.g.
524 // <meta name="font-size-adjustment" content="-2" />
525 // useful when slides have too much content ;-)
526
527 if (0 <= sizeIndex + sizeAdjustment &&
528 sizeIndex + sizeAdjustment < sizes.length)
529 sizeIndex = sizeIndex + sizeAdjustment;
530
531 // enables cross browser use of relative width/height
532 // on object elements for use with SVG and Flash media
533 adjustObjectDimensions(width, height);
534
535 document.body.style.fontSize = sizes[sizeIndex];
536
537 lastWidth = width;
538 lastHeight = height;
539
540 // force reflow to work around Mozilla bug
541 //if (ns_pos)
542 {
543 var slide = slides[slidenum];
544 hideSlide(slide);
545 showSlide(slide);
546 }
547
548 // force correct positioning of toolbar
549 refreshToolbar(200);
550 }
551 }
552
553 function scrolled()
554 {
555 if (toolbar && !ns_pos && !ie7)
556 {
557 hackoffset = scrollXOffset();
558 // hide toolbar
559 toolbar.style.display = "none";
560
561 // make it reappear later
562 if (scrollhack == 0 && !viewAll)
563 {
564 setTimeout(showToolbar, 1000);
565 scrollhack = 1;
566 }
567 }
568 }
569
570 // used to ensure IE refreshes toolbar in correct position
571 function refreshToolbar(interval)
572 {
573 if (!ns_pos && !ie7)
574 {
575 hideToolbar();
576 setTimeout(showToolbar, interval);
577 }
578 }
579
580 // restores toolbar after short delay
581 function showToolbar()
582 {
583 if (wantToolbar)
584 {
585 if (!ns_pos)
586 {
587 // adjust position to allow for scrolling
588 var xoffset = scrollXOffset();
589 toolbar.style.left = xoffset;
590 toolbar.style.right = xoffset;
591
592 // determine vertical scroll offset
593 //var yoffset = scrollYOffset();
594
595 // bottom is doc height - window height - scroll offset
596 //var bottom = documentHeight() - lastHeight - yoffset
597
598 //if (yoffset > 0 || documentHeight() > lastHeight)
599 // bottom += 16; // allow for height of scrollbar
600
601 toolbar.style.bottom = 0; //bottom;
602 }
603
604 toolbar.style.display = "block";
605 toolbar.style.visibility = "visible";
606 }
607
608 scrollhack = 0;
609
610
611 // set the keyboard focus to the help link on the
612 // toolbar to ensure that document has the focus
613 // IE doesn't always work with window.focus()
614 // and this hack has benefit of Enter for help
615
616 try
617 {
618 if (!opera)
619 helpAnchor.focus();
620 }
621 catch (e)
622 {
623 }
624 }
625
626 function hideToolbar()
627 {
628 toolbar.style.display = "none";
629 toolbar.style.visibility = "hidden";
630 window.focus();
631 }
632
633 // invoked via F key
634 function toggleToolbar()
635 {
636 if (!viewAll)
637 {
638 if (toolbar.style.display == "none")
639 {
640 toolbar.style.display = "block";
641 toolbar.style.visibility = "visible";
642 wantToolbar = 1;
643 }
644 else
645 {
646 toolbar.style.display = "none";
647 toolbar.style.visibility = "hidden";
648 wantToolbar = 0;
649 }
650 }
651 }
652
653 function scrollXOffset()
654 {
655 if (window.pageXOffset)
656 return self.pageXOffset;
657
658 if (document.documentElement &&
659 document.documentElement.scrollLeft)
660 return document.documentElement.scrollLeft;
661
662 if (document.body)
663 return document.body.scrollLeft;
664
665 return 0;
666 }
667
668
669 function scrollYOffset()
670 {
671 if (window.pageYOffset)
672 return self.pageYOffset;
673
674 if (document.documentElement &&
675 document.documentElement.scrollTop)
676 return document.documentElement.scrollTop;
677
678 if (document.body)
679 return document.body.scrollTop;
680
681 return 0;
682 }
683
684 // looking for a way to determine height of slide content
685 // the slide itself is set to the height of the window
686 function optimizeFontSize()
687 {
688 var slide = slides[slidenum];
689
690 //var dh = documentHeight(); //getDocHeight(document);
691 var dh = slide.scrollHeight;
692 var wh = getWindowHeight();
693 var u = 100 * dh / wh;
694
695 alert("window utilization = " + u + "% (doc "
696 + dh + " win " + wh + ")");
697 }
698
699 function getDocHeight(doc) // from document object
700 {
701 if (!doc)
702 doc = document;
703
704 if (doc && doc.body && doc.body.offsetHeight)
705 return doc.body.offsetHeight; // ns/gecko syntax
706
707 if (doc && doc.body && doc.body.scrollHeight)
708 return doc.body.scrollHeight;
709
710 alert("couldn't determine document height");
711 }
712
713 function getWindowHeight()
714 {
715 if ( typeof( window.innerHeight ) == 'number' )
716 return window.innerHeight; // Non IE browser
717
718 if (document.documentElement && document.documentElement.clientHeight)
719 return document.documentElement.clientHeight; // IE6
720
721 if (document.body && document.body.clientHeight)
722 return document.body.clientHeight; // IE4
723 }
724
725
726
727 function documentHeight()
728 {
729 var sh, oh;
730
731 sh = document.body.scrollHeight;
732 oh = document.body.offsetHeight;
733
734 if (sh && oh)
735 {
736 return (sh > oh ? sh : oh);
737 }
738
739 // no idea!
740 return 0;
741 }
742
743 function smaller()
744 {
745 if (sizeIndex > 0)
746 {
747 --sizeIndex;
748 }
749
750 toolbar.style.display = "none";
751 document.body.style.fontSize = sizes[sizeIndex];
752 var slide = slides[slidenum];
753 hideSlide(slide);
754 showSlide(slide);
755 setTimeout(showToolbar, 300);
756 }
757
758 function bigger()
759 {
760 if (sizeIndex < sizes.length - 1)
761 {
762 ++sizeIndex;
763 }
764
765 toolbar.style.display = "none";
766 document.body.style.fontSize = sizes[sizeIndex];
767 var slide = slides[slidenum];
768 hideSlide(slide);
769 showSlide(slide);
770 setTimeout(showToolbar, 300);
771 }
772
773 // enables cross browser use of relative width/height
774 // on object elements for use with SVG and Flash media
775 // with thanks to Ivan Herman for the suggestion
776 function adjustObjectDimensions(width, height)
777 {
778 for( var i = 0; i < objects.length; i++ )
779 {
780 var obj = objects[i];
781 var mimeType = obj.getAttribute("type");
782
783 if (mimeType == "image/svg+xml" || mimeType == "application/x-shockwave-flash")
784 {
785 if ( !obj.initialWidth )
786 obj.initialWidth = obj.getAttribute("width");
787
788 if ( !obj.initialHeight )
789 obj.initialHeight = obj.getAttribute("height");
790
791 if ( obj.initialWidth && obj.initialWidth.charAt(obj.initialWidth.length-1) == "%" )
792 {
793 var w = parseInt(obj.initialWidth.slice(0, obj.initialWidth.length-1));
794 var newW = width * (w/100.0);
795 obj.setAttribute("width",newW);
796 }
797
798 if ( obj.initialHeight && obj.initialHeight.charAt(obj.initialHeight.length-1) == "%" )
799 {
800 var h = parseInt(obj.initialHeight.slice(0, obj.initialHeight.length-1));
801 var newH = height * (h/100.0);
802 obj.setAttribute("height", newH);
803 }
804 }
805 }
806 }
807
808 function cancel(event)
809 {
810 if (event)
811 {
812 event.cancel = true;
813 event.returnValue = false;
814
815 if (event.preventDefault)
816 event.preventDefault();
817 }
818
819 return false;
820 }
821
822 // See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
823 function keyDown(event)
824 {
825 var key;
826
827 if (!event)
828 var event = window.event;
829
830 key_wanted = false;
831
832 // kludge around NS/IE differences
833 if (window.event)
834 key = window.event.keyCode;
835 else if (event.which)
836 key = event.which;
837 else
838 return true; // Yikes! unknown browser
839
840 // ignore event if key value is zero
841 // as for alt on Opera and Konqueror
842 if (!key)
843 return true;
844
845 // check for concurrent control/command/alt key
846 // but are these only present on mouse events?
847
848 if (event.ctrlKey || event.altKey || event.metaKey)
849 return true;
850
851 // dismiss table of contents if visible
852 if (isShownToc() && key != 9 && key != 16 && key != 38 && key != 40)
853 {
854 hideTableOfContents();
855
856 if (key == 27 || key == 84 || key == 67)
857 return cancel(event);
858 }
859
860 key_wanted = true;
861
862 if (key == 34) // Page Down
863 {
864 if (viewAll)
865 return true;
866
867 nextSlide(false);
868 return cancel(event);
869 }
870 else if (key == 33) // Page Up
871 {
872 if (viewAll)
873 return true;
874
875 previousSlide(false);
876 return cancel(event);
877 }
878 else if (key == 32) // space bar
879 {
880 nextSlide(true);
881 return cancel(event);
882 }
883 else if (key == 37) // Left arrow
884 {
885 previousSlide(!event.shiftKey);
886 return cancel(event);
887 }
888 else if (key == 36) // Home
889 {
890 firstSlide();
891 return cancel(event);
892 }
893 else if (key == 35) // End
894 {
895 lastSlide();
896 return cancel(event);
897 }
898 else if (key == 39) // Right arrow
899 {
900 nextSlide(!event.shiftKey);
901 return cancel(event);
902 }
903 else if (key == 13) // Enter
904 {
905 if (outline)
906 {
907 if (outline.visible)
908 fold(outline);
909 else
910 unfold(outline);
911
912 return cancel(event);
913 }
914 }
915 else if (key == 188) // < for smaller fonts
916 {
917 smaller();
918 return cancel(event);
919 }
920 else if (key == 190) // > for larger fonts
921 {
922 bigger();
923 return cancel(event);
924 }
925 else if (key == 189 || key == 109) // - for smaller fonts
926 {
927 smaller();
928 return cancel(event);
929 }
930 else if (key == 187 || key == 191 || key == 107) // = + for larger fonts
931 {
932 bigger();
933 return cancel(event);
934 }
935 else if (key == 83) // S for smaller fonts
936 {
937 smaller();
938 return cancel(event);
939 }
940 else if (key == 66) // B for larger fonts
941 {
942 bigger();
943 return cancel(event);
944 }
945 else if (key == 90) // Z for last slide
946 {
947 lastSlide();
948 return cancel(event);
949 }
950 else if (key == 70) // F for toggle toolbar
951 {
952 toggleToolbar();
953 return cancel(event);
954 }
955 else if (key == 65) // A for toggle view single/all slides
956 {
957 toggleView();
958 return cancel(event);
959 }
960 else if (key == 75) // toggle action of left click for next page
961 {
962 mouseClickEnabled = !mouseClickEnabled;
963 alert((mouseClickEnabled ? "enabled" : "disabled") + " mouse click advance");
964 return cancel(event);
965 }
966 else if (key == 84 || key == 67) // T or C for table of contents
967 {
968 if (toc)
969 showTableOfContents();
970
971 return cancel(event);
972 }
973 else if (key == 72) // H for help
974 {
975 window.location = helpPage;
976 return cancel(event);
977 }
978
979 //else if (key == 93) // Windows menu key
980 //alert("lastShown is " + lastShown);
981 //else alert("key code is "+ key);
982
983 key_wanted = false;
984 return true;
985 }
986
987 // only used for Opera
988 function keyPress(event)
989 {
990 if (!event)
991 event = window.event
992
993 return key_wanted ? cancel(event) : true;
994 }
995
996 // make note of length of selected text
997 // as this evaluates to zero in click event
998 function mouseButtonUp(e)
999 {
1000 selectedTextLen = getSelectedText().length;
1001 }
1002
1003 // right mouse button click is reserved for context menus
1004 // it is more reliable to detect rightclick than leftclick
1005 function mouseButtonClick(e)
1006 {
1007 var rightclick = false;
1008 var leftclick = false;
1009 var middleclick = false;
1010 var target;
1011
1012 if (!e)
1013 var e = window.event;
1014
1015 if (e.target)
1016 target = e.target;
1017 else if (e.srcElement)
1018 target = e.srcElement;
1019
1020 // work around Safari bug
1021 if (target.nodeType == 3)
1022 target = target.parentNode;
1023
1024 if (e.which) // all browsers except IE
1025 {
1026 leftclick = (e.which == 1);
1027 middleclick = (e.which == 2);
1028 rightclick = (e.which == 3);
1029 }
1030 else if (e.button)
1031 {
1032 // Konqueror gives 1 for left, 4 for middle
1033 // IE6 gives 0 for left and not 1 as I expected
1034
1035 if (e.button == 4)
1036 middleclick = true;
1037
1038 // all browsers agree on 2 for right button
1039 rightclick = (e.button == 2);
1040 }
1041 else leftclick = true;
1042
1043 //alert("selected text length = "+selectedTextLen);
1044
1045 if (selectedTextLen > 0)
1046 {
1047 stopPropagation(e);
1048 e.cancel = true;
1049 e.returnValue = false;
1050 return false;
1051 }
1052
1053 // dismiss table of contents
1054 hideTableOfContents();
1055
1056 // check if target is something that probably want's clicks
1057 // e.g. embed, object, input, textarea, select, option
1058
1059 if (mouseClickEnabled && leftclick &&
1060 target.nodeName != "EMBED" &&
1061 target.nodeName != "OBJECT" &&
1062 target.nodeName != "VIDEO" &&
1063 target.nodeName != "INPUT" &&
1064 target.nodeName != "TEXTAREA" &&
1065 target.nodeName != "SELECT" &&
1066 target.nodeName != "OPTION")
1067 {
1068 nextSlide(true);
1069 stopPropagation(e);
1070 e.cancel = true;
1071 e.returnValue = false;
1072 }
1073 }
1074
1075 function previousSlide(incremental)
1076 {
1077 if (!viewAll)
1078 {
1079 var slide;
1080
1081 if ((incremental || slidenum == 0) && lastShown != null)
1082 {
1083 lastShown = hidePreviousItem(lastShown);
1084 setEosStatus(false);
1085 }
1086 else if (slidenum > 0)
1087 {
1088 slide = slides[slidenum];
1089 hideSlide(slide);
1090
1091 slidenum = slidenum - 1;
1092 slide = slides[slidenum];
1093 setVisibilityAllIncremental("visible");
1094 lastShown = previousIncrementalItem(null);
1095 setEosStatus(true);
1096 showSlide(slide);
1097 }
1098
1099 setLocation();
1100
1101 if (!ns_pos)
1102 refreshToolbar(200);
1103 }
1104 }
1105
1106 function nextSlide(incremental)
1107 {
1108 if (!viewAll)
1109 {
1110 var slide, last = lastShown;
1111
1112 if (incremental || slidenum == slides.length - 1)
1113 lastShown = revealNextItem(lastShown);
1114
1115 if ((!incremental || lastShown == null) && slidenum < slides.length - 1)
1116 {
1117 slide = slides[slidenum];
1118 hideSlide(slide);
1119
1120 slidenum = slidenum + 1;
1121 slide = slides[slidenum];
1122 lastShown = null;
1123 setVisibilityAllIncremental("hidden");
1124 showSlide(slide);
1125 }
1126 else if (!lastShown)
1127 {
1128 if (last && incremental)
1129 lastShown = last;
1130 }
1131
1132 setLocation();
1133
1134 setEosStatus(!nextIncrementalItem(lastShown));
1135
1136 if (!ns_pos)
1137 refreshToolbar(200);
1138 }
1139 }
1140
1141 // to first slide with nothing revealed
1142 // i.e. state at start of presentation
1143 function firstSlide()
1144 {
1145 if (!viewAll)
1146 {
1147 var slide;
1148
1149 if (slidenum != 0)
1150 {
1151 slide = slides[slidenum];
1152 hideSlide(slide);
1153
1154 slidenum = 0;
1155 slide = slides[slidenum];
1156 lastShown = null;
1157 setVisibilityAllIncremental("hidden");
1158 showSlide(slide);
1159 }
1160
1161 setEosStatus(!nextIncrementalItem(lastShown));
1162 setLocation();
1163 }
1164 }
1165
1166
1167 // to last slide with everything revealed
1168 // i.e. state at end of presentation
1169 function lastSlide()
1170 {
1171 if (!viewAll)
1172 {
1173 var slide;
1174
1175 lastShown = null; //revealNextItem(lastShown);
1176
1177 if (lastShown == null && slidenum < slides.length - 1)
1178 {
1179 slide = slides[slidenum];
1180 hideSlide(slide);
1181 slidenum = slides.length - 1;
1182 slide = slides[slidenum];
1183 setVisibilityAllIncremental("visible");
1184 lastShown = previousIncrementalItem(null);
1185
1186 showSlide(slide);
1187 }
1188 else
1189 {
1190 setVisibilityAllIncremental("visible");
1191 lastShown = previousIncrementalItem(null);
1192 }
1193
1194 setEosStatus(true);
1195 setLocation();
1196 }
1197 }
1198
1199 // first slide is 0
1200 function gotoSlide(num)
1201 {
1202 //alert("going to slide " + (num+1));
1203 var slide = slides[slidenum];
1204 hideSlide(slide);
1205 slidenum = num;
1206 slide = slides[slidenum];
1207 lastShown = null;
1208 setVisibilityAllIncremental("hidden");
1209 setEosStatus(!nextIncrementalItem(lastShown));
1210 document.title = title + " (" + (slidenum+1) + ")";
1211 showSlide(slide);
1212 showSlideNumber();
1213 }
1214
1215 function setEosStatus(state)
1216 {
1217 if (eos)
1218 eos.style.color = (state ? "rgb(240,240,240)" : "red");
1219 }
1220
1221 function showSlide(slide)
1222 {
1223 syncBackground(slide);
1224 window.scrollTo(0,0);
1225 slide.style.visibility = "visible";
1226 slide.style.display = "block";
1227 }
1228
1229 function hideSlide(slide)
1230 {
1231 slide.style.visibility = "hidden";
1232 slide.style.display = "none";
1233 }
1234
1235 function beforePrint()
1236 {
1237 showAllSlides();
1238 hideToolbar();
1239 }
1240
1241 function afterPrint()
1242 {
1243 if (!viewAll)
1244 {
1245 singleSlideView();
1246 showToolbar();
1247 }
1248 }
1249
1250 function printSlides()
1251 {
1252 beforePrint();
1253 window.print();
1254 afterPrint();
1255 }
1256
1257 function toggleView()
1258 {
1259 if (viewAll)
1260 {
1261 singleSlideView();
1262 showToolbar();
1263 viewAll = 0;
1264 }
1265 else
1266 {
1267 showAllSlides();
1268 hideToolbar();
1269 viewAll = 1;
1270 }
1271 }
1272
1273 // prepare for printing
1274 function showAllSlides()
1275 {
1276 var slide;
1277
1278 for (var i = 0; i < slides.length; ++i)
1279 {
1280 slide = slides[i];
1281
1282 slide.style.position = "relative";
1283 slide.style.borderTopStyle = "solid";
1284 slide.style.borderTopWidth = "thin";
1285 slide.style.borderTopColor = "black";
1286
1287 try {
1288 if (i == 0)
1289 slide.style.pageBreakBefore = "avoid";
1290 else
1291 slide.style.pageBreakBefore = "always";
1292 }
1293 catch (e)
1294 {
1295 //do nothing
1296 }
1297
1298 setVisibilityAllIncremental("visible");
1299 showSlide(slide);
1300 }
1301
1302 var note;
1303
1304 for (var i = 0; i < notes.length; ++i)
1305 {
1306 showSlide(notes[i]);
1307 }
1308
1309 // no easy way to render background under each slide
1310 // without duplicating the background divs for each slide
1311 // therefore hide backgrounds to avoid messing up slides
1312 hideBackgrounds();
1313 }
1314
1315 // restore after printing
1316 function singleSlideView()
1317 {
1318 var slide;
1319
1320 for (var i = 0; i < slides.length; ++i)
1321 {
1322 slide = slides[i];
1323
1324 slide.style.position = "absolute";
1325
1326 if (i == slidenum)
1327 {
1328 slide.style.borderStyle = "none";
1329 showSlide(slide);
1330 }
1331 else
1332 {
1333 slide.style.borderStyle = "none";
1334 hideSlide(slide);
1335 }
1336 }
1337
1338 setVisibilityAllIncremental("visible");
1339 lastShown = previousIncrementalItem(null);
1340
1341 var note;
1342
1343 for (var i = 0; i < notes.length; ++i)
1344 {
1345 hideSlide(notes[i]);
1346 }
1347 }
1348
1349 // the string str is a whitespace separated list of tokens
1350 // test if str contains a particular token, e.g. "slide"
1351 function hasToken(str, token)
1352 {
1353 if (str)
1354 {
1355 // define pattern as regular expression
1356 var pattern = /\w+/g;
1357
1358 // check for matches
1359 // place result in array
1360 var result = str.match(pattern);
1361
1362 // now check if desired token is present
1363 for (var i = 0; i < result.length; i++)
1364 {
1365 if (result[i] == token)
1366 return true;
1367 }
1368 }
1369
1370 return false;
1371 }
1372
1373 function getClassList(element)
1374 {
1375 if (typeof element.className != 'undefined')
1376 return element.className;
1377
1378 var clsname = (ns_pos||ie8) ? "class" : "className";
1379 return element.getAttribute(clsname);
1380 }
1381
1382 function hasClass(element, name)
1383 {
1384 var regexp = new RegExp("(^| )" + name + "\W*");
1385
1386 if (typeof element.className != 'undefined')
1387 return regexp.test(element.className);
1388
1389 var clsname = (ns_pos||ie8) ? "class" : "className";
1390 return regexp.test(element.getAttribute(clsname));
1391 }
1392
1393 function removeClass(element, name)
1394 {
1395 var regexp = new RegExp("(^| )" + name + "\W*");
1396 var clsval = "";
1397
1398 if (typeof element.className != 'undefined')
1399 {
1400 clsval = element.className;
1401
1402 if (clsval)
1403 {
1404 clsval = clsval.replace(regexp, "");
1405 element.className = clsval;
1406 }
1407 }
1408 else
1409 {
1410 var clsname = (ns_pos||ie8) ? "class" : "className";
1411 clsval = element.getAttribute(clsname);
1412
1413 if (clsval)
1414 {
1415 clsval = clsval.replace(regexp, "");
1416 element.setAttribute(clsname, clsval);
1417 }
1418 }
1419 }
1420
1421 function addClass(element, name)
1422 {
1423 if (!hasClass(element, name))
1424 {
1425 if (typeof element.className != 'undefined')
1426 element.className += " " + name;
1427 else
1428 {
1429 var clsname = (ns_pos||ie8) ? "class" : "className";
1430 var clsval = element.getAttribute(clsname);
1431 clsval = clsval ? clsval + " " + name : name;
1432 element.setAttribute(clsname, clsval);
1433 }
1434 }
1435 }
1436
1437 // wysiwyg editors make it hard to use div elements
1438 // e.g. amaya loses the div when you copy and paste
1439 // this function wraps div elements around implicit
1440 // slides which start with an h1 element and continue
1441 // up to the next heading or div element
1442 function wrapImplicitSlides()
1443 {
1444 var i, heading, node, next, div;
1445 var headings = document.getElementsByTagName("h1");
1446
1447 if (!headings)
1448 return;
1449
1450 for (i = 0; i < headings.length; ++i)
1451 {
1452 heading = headings[i];
1453
1454 if (heading.parentNode != document.body)
1455 continue;
1456
1457 node = heading.nextSibling;
1458
1459 div = document.createElement("div");
1460 addClass(div, "slide");
1461 document.body.replaceChild(div, heading);
1462 div.appendChild(heading);
1463
1464 while (node)
1465 {
1466 if (node.nodeType == 1 && // an element
1467 (node.nodeName == "H1" ||
1468 node.nodeName == "h1" ||
1469 node.nodeName == "DIV" ||
1470 node.nodeName == "div"))
1471 break;
1472
1473 next = node.nextSibling;
1474 node = document.body.removeChild(node);
1475 div.appendChild(node);
1476 node = next;
1477 }
1478 }
1479 }
1480
1481 // return new array of all slides
1482 function collectSlides()
1483 {
1484 var slides = new Array();
1485 var divs = document.body.getElementsByTagName("div");
1486
1487 for (var i = 0; i < divs.length; ++i)
1488 {
1489 div = divs.item(i);
1490
1491 if (hasClass(div, "slide"))
1492 {
1493 // add slide to collection
1494 slides[slides.length] = div;
1495
1496 // hide each slide as it is found
1497 div.style.display = "none";
1498 div.style.visibility = "hidden";
1499
1500 // add dummy <br/> at end for scrolling hack
1501 var node1 = document.createElement("br");
1502 div.appendChild(node1);
1503 var node2 = document.createElement("br");
1504 div.appendChild(node2);
1505 }
1506 else if (hasClass(div, "background"))
1507 { // work around for Firefox SVG reload bug
1508 // which otherwise replaces 1st SVG graphic with 2nd
1509 div.style.display = "block";
1510 }
1511 }
1512
1513 return slides;
1514 }
1515
1516 // return new array of all <div class="handout">
1517 function collectNotes()
1518 {
1519 var notes = new Array();
1520 var divs = document.body.getElementsByTagName("div");
1521
1522 for (var i = 0; i < divs.length; ++i)
1523 {
1524 div = divs.item(i);
1525
1526 if (hasClass(div, "handout"))
1527 {
1528 // add slide to collection
1529 notes[notes.length] = div;
1530
1531 // hide handout notes as they are found
1532 div.style.display = "none";
1533 div.style.visibility = "hidden";
1534 }
1535 }
1536
1537 return notes;
1538 }
1539
1540 // return new array of all <div class="background">
1541 // including named backgrounds e.g. class="background titlepage"
1542 function collectBackgrounds()
1543 {
1544 var backgrounds = new Array();
1545 var divs = document.body.getElementsByTagName("div");
1546
1547 for (var i = 0; i < divs.length; ++i)
1548 {
1549 div = divs.item(i);
1550
1551 if (hasClass(div, "background"))
1552 {
1553 // add slide to collection
1554 backgrounds[backgrounds.length] = div;
1555
1556 // hide named backgrounds as they are found
1557 // e.g. class="background epilog"
1558 if (getClassList(div) != "background")
1559 {
1560 div.style.display = "none";
1561 div.style.visibility = "hidden";
1562 }
1563 }
1564 }
1565
1566 return backgrounds;
1567 }
1568
1569 // show just the backgrounds pertinent to this slide
1570 function syncBackground(slide)
1571 {
1572 var background;
1573 var bgColor;
1574
1575 if (slide.currentStyle)
1576 bgColor = slide.currentStyle["backgroundColor"];
1577 else if (document.defaultView)
1578 {
1579 var styles = document.defaultView.getComputedStyle(slide,null);
1580
1581 if (styles)
1582 bgColor = styles.getPropertyValue("background-color");
1583 else // broken implementation probably due Safari or Konqueror
1584 {
1585 //alert("defective implementation of getComputedStyle()");
1586 bgColor = "transparent";
1587 }
1588 }
1589 else
1590 bgColor == "transparent";
1591
1592 if (bgColor == "transparent")
1593 {
1594 var slideClass = getClassList(slide);
1595
1596 for (var i = 0; i < backgrounds.length; i++)
1597 {
1598 background = backgrounds[i];
1599
1600 var bgClass = getClassList(background);
1601
1602 if (matchingBackground(slideClass, bgClass))
1603 {
1604 background.style.display = "block";
1605 background.style.visibility = "visible";
1606 }
1607 else
1608 {
1609 background.style.display = "none";
1610 background.style.visibility = "hidden";
1611 }
1612 }
1613 }
1614 else // forcibly hide all backgrounds
1615 hideBackgrounds();
1616 }
1617
1618 function hideBackgrounds()
1619 {
1620 for (var i = 0; i < backgrounds.length; i++)
1621 {
1622 background = backgrounds[i];
1623 background.style.display = "none";
1624 background.style.visibility = "hidden";
1625 }
1626 }
1627
1628 // compare classes for slide and background
1629 function matchingBackground(slideClass, bgClass)
1630 {
1631 if (bgClass == "background")
1632 return true;
1633
1634 // define pattern as regular expression
1635 var pattern = /\w+/g;
1636
1637 // check for matches and place result in array
1638 var result = slideClass.match(pattern);
1639
1640 // now check if desired name is present for background
1641 for (var i = 0; i < result.length; i++)
1642 {
1643 if (hasToken(bgClass, result[i]))
1644 return true;
1645 }
1646
1647 return false;
1648 }
1649
1650 // left to right traversal of root's content
1651 function nextNode(root, node)
1652 {
1653 if (node == null)
1654 return root.firstChild;
1655
1656 if (node.firstChild)
1657 return node.firstChild;
1658
1659 if (node.nextSibling)
1660 return node.nextSibling;
1661
1662 for (;;)
1663 {
1664 node = node.parentNode;
1665
1666 if (!node || node == root)
1667 break;
1668
1669 if (node && node.nextSibling)
1670 return node.nextSibling;
1671 }
1672
1673 return null;
1674 }
1675
1676 // right to left traversal of root's content
1677 function previousNode(root, node)
1678 {
1679 if (node == null)
1680 {
1681 node = root.lastChild;
1682
1683 if (node)
1684 {
1685 while (node.lastChild)
1686 node = node.lastChild;
1687 }
1688
1689 return node;
1690 }
1691
1692 if (node.previousSibling)
1693 {
1694 node = node.previousSibling;
1695
1696 while (node.lastChild)
1697 node = node.lastChild;
1698
1699 return node;
1700 }
1701
1702 if (node.parentNode != root)
1703 return node.parentNode;
1704
1705 return null;
1706 }
1707
1708 // HTML elements that can be used with class="incremental"
1709 // note that you can also put the class on containers like
1710 // up, ol, dl, and div to make their contents appear
1711 // incrementally. Upper case is used since this is what
1712 // browsers report for HTML node names (text/html).
1713 function incrementalElementList()
1714 {
1715 var inclist = new Array();
1716 inclist["P"] = true;
1717 inclist["PRE"] = true;
1718 inclist["LI"] = true;
1719 inclist["BLOCKQUOTE"] = true;
1720 inclist["DT"] = true;
1721 inclist["DD"] = true;
1722 inclist["H2"] = true;
1723 inclist["H3"] = true;
1724 inclist["H4"] = true;
1725 inclist["H5"] = true;
1726 inclist["H6"] = true;
1727 inclist["SPAN"] = true;
1728 inclist["ADDRESS"] = true;
1729 inclist["TABLE"] = true;
1730 inclist["TR"] = true;
1731 inclist["TH"] = true;
1732 inclist["TD"] = true;
1733 inclist["IMG"] = true;
1734 inclist["OBJECT"] = true;
1735 return inclist;
1736 }
1737
1738 function nextIncrementalItem(node)
1739 {
1740 var slide = slides[slidenum];
1741
1742 for (;;)
1743 {
1744 node = nextNode(slide, node);
1745
1746 if (node == null || node.parentNode == null)
1747 break;
1748
1749 if (node.nodeType == 1) // ELEMENT
1750 {
1751 if (node.nodeName == "BR")
1752 continue;
1753
1754 if (hasClass(node, "incremental")
1755 && okayForIncremental[node.nodeName])
1756 return node;
1757
1758 if (hasClass(node.parentNode, "incremental")
1759 && !hasClass(node, "non-incremental"))
1760 return node;
1761 }
1762 }
1763
1764 return node;
1765 }
1766
1767 function previousIncrementalItem(node)
1768 {
1769 var slide = slides[slidenum];
1770
1771 for (;;)
1772 {
1773 node = previousNode(slide, node);
1774
1775 if (node == null || node.parentNode == null)
1776 break;
1777
1778 if (node.nodeType == 1)
1779 {
1780 if (node.nodeName == "BR")
1781 continue;
1782
1783 if (hasClass(node, "incremental")
1784 && okayForIncremental[node.nodeName])
1785 return node;
1786
1787 if (hasClass(node.parentNode, "incremental")
1788 && !hasClass(node, "non-incremental"))
1789 return node;
1790 }
1791 }
1792
1793 return node;
1794 }
1795
1796 // set visibility for all elements on current slide with
1797 // a parent element with attribute class="incremental"
1798 function setVisibilityAllIncremental(value)
1799 {
1800 var node = nextIncrementalItem(null);
1801
1802 while (node)
1803 {
1804 node.style.visibility = value;
1805 node = nextIncrementalItem(node);
1806 }
1807 }
1808
1809 // reveal the next hidden item on the slide
1810 // node is null or the node that was last revealed
1811 function revealNextItem(node)
1812 {
1813 node = nextIncrementalItem(node);
1814
1815 if (node && node.nodeType == 1) // an element
1816 node.style.visibility = "visible";
1817
1818 return node;
1819 }
1820
1821
1822 // exact inverse of revealNextItem(node)
1823 function hidePreviousItem(node)
1824 {
1825 if (node && node.nodeType == 1) // an element
1826 node.style.visibility = "hidden";
1827
1828 return previousIncrementalItem(node);
1829 }
1830
1831
1832 /* set click handlers on all anchors */
1833 function patchAnchors()
1834 {
1835 var anchors = document.body.getElementsByTagName("a");
1836
1837 for (var i = 0; i < anchors.length; ++i)
1838 {
1839 anchors[i].onclick = clickedAnchor;
1840 }
1841 }
1842
1843 function clickedAnchor(e)
1844 {
1845 if (!e)
1846 var e = window.event;
1847
1848 // compare this.href with location.href
1849 // for link to another slide in this doc
1850
1851 if (pageAddress(this.href) == pageAddress(location.href))
1852 {
1853 // yes, so find new slide number
1854 var newslidenum = findSlideNumber(this.href);
1855
1856 if (newslidenum != slidenum)
1857 {
1858 slide = slides[slidenum];
1859 hideSlide(slide);
1860 slidenum = newslidenum;
1861 slide = slides[slidenum];
1862 showSlide(slide);
1863 setLocation();
1864 }
1865 }
1866 else if (this.target == null)
1867 location.href = this.href;
1868
1869 this.blur();
1870 stopPropagation(e);
1871 }
1872
1873 function pageAddress(uri)
1874 {
1875 var i = uri.indexOf("#");
1876
1877 if (i < 0)
1878 i = uri.indexOf("%23");
1879
1880 // check if anchor is entire page
1881
1882 if (i < 0)
1883 return uri; // yes
1884
1885 return uri.substr(0, i);
1886 }
1887
1888 function showSlideNumber()
1889 {
1890 slideNumElement.innerHTML = "slide".localize() + " " +
1891 (slidenum + 1) + "/" + slides.length;
1892 }
1893
1894 // every 200mS check if the location has been changed as a
1895 // result of the user activating the Back button/menu item
1896 // doesn't work for Opera < 9.5
1897 function checkLocation()
1898 {
1899 var hash = location.hash;
1900
1901 if (slidenum > 0 && (hash == "" || hash == "#"))
1902 gotoSlide(0);
1903 else if (hash.length > 2 && hash != "#("+(slidenum+1)+")")
1904 {
1905 var num = parseInt(location.hash.substr(2));
1906
1907 if (!isNaN(num))
1908 gotoSlide(num-1);
1909 }
1910 }
1911
1912 // this doesn't push location onto history stack for IE
1913 // for which a hidden iframe hack is needed: load page into
1914 // the iframe with script that set's parent's location.hash
1915 // but that won't work for standalone use unless we can
1916 // create the page dynamically via a javascript: URL
1917 function setLocation()
1918 {
1919 var uri = pageAddress(location.href);
1920 var hash = "#(" + (slidenum+1) + ")";
1921
1922 if (slidenum >= 0)
1923 uri = uri + hash;
1924
1925 if (ie && !ie8)
1926 pushHash(hash);
1927
1928 if (uri != location.href /*&& !khtml */)
1929 location.href = uri;
1930
1931 if (khtml)
1932 hash = "(" + (slidenum+1) + ")";
1933
1934 if (!ie && location.hash != hash && location.hash != "")
1935 location.hash = hash;
1936
1937 document.title = title + " (" + (slidenum+1) + ")";
1938 showSlideNumber();
1939 }
1940
1941 // only used for IE6 and IE7
1942 function onFrameLoaded(hash)
1943 {
1944 location.hash = hash;
1945 var uri = pageAddress(location.href);
1946 location.href = uri + hash;
1947 }
1948
1949 // history hack with thanks to Bertrand Le Roy
1950 function pushHash(hash)
1951 {
1952 if (hash == "") hash = "#(1)";
1953 window.location.hash = hash;
1954 var doc = document.getElementById("historyFrame").contentWindow.document;
1955 doc.open("javascript:'<html></html>'");
1956 doc.write("<html><head><script type=\"text/javascript\">parent.onFrameLoaded('"+
1957 (hash) + "');</script></head><body>hello mum</body></html>");
1958 doc.close();
1959 }
1960
1961 // find current slide based upon location
1962 // first find target anchor and then look
1963 // for associated div element enclosing it
1964 // finally map that to slide number
1965 function findSlideNumber(uri)
1966 {
1967 // first get anchor from page location
1968
1969 var i = uri.indexOf("#");
1970
1971 // check if anchor is entire page
1972
1973 if (i < 0)
1974 return 0; // yes
1975
1976 var anchor = unescape(uri.substr(i+1));
1977
1978 // now use anchor as XML ID to find target
1979 var target = document.getElementById(anchor);
1980
1981 if (!target)
1982 {
1983 // does anchor look like "(2)" for slide 2 ??
1984 // where first slide is (1)
1985 var re = /\((\d)+\)/;
1986
1987 if (anchor.match(re))
1988 {
1989 var num = parseInt(anchor.substring(1, anchor.length-1));
1990
1991 if (num > slides.length)
1992 num = 1;
1993
1994 if (--num < 0)
1995 num = 0;
1996
1997 return num;
1998 }
1999
2000 // accept [2] for backwards compatibility
2001 re = /\[(\d)+\]/;
2002
2003 if (anchor.match(re))
2004 {
2005 var num = parseInt(anchor.substring(1, anchor.length-1));
2006
2007 if (num > slides.length)
2008 num = 1;
2009
2010 if (--num < 0)
2011 num = 0;
2012
2013 return num;
2014 }
2015
2016 // oh dear unknown anchor
2017 return 0;
2018 }
2019
2020 // search for enclosing slide
2021
2022 while (true)
2023 {
2024 // browser coerces html elements to uppercase!
2025 if (target.nodeName.toLowerCase() == "div" &&
2026 hasClass(target, "slide"))
2027 {
2028 // found the slide element
2029 break;
2030 }
2031
2032 // otherwise try parent element if any
2033
2034 target = target.parentNode;
2035
2036 if (!target)
2037 {
2038 return 0; // no luck!
2039 }
2040 };
2041
2042 for (i = 0; i < slides.length; ++i)
2043 {
2044 if (slides[i] == target)
2045 return i; // success
2046 }
2047
2048 // oh dear still no luck
2049 return 0;
2050 }
2051
2052 // find slide name from first h1 element
2053 // default to document title + slide number
2054 function slideName(index)
2055 {
2056 var name = null;
2057 var slide = slides[index];
2058
2059 var heading = findHeading(slide);
2060
2061 if (heading)
2062 name = extractText(heading);
2063
2064 if (!name)
2065 name = title + "(" + (index + 1) + ")";
2066
2067 name.replace(/\&/g, "&amp;");
2068 name.replace(/\</g, "&lt;");
2069 name.replace(/\>/g, "&gt;");
2070
2071 return name;
2072 }
2073
2074 // find first h1 element in DOM tree
2075 function findHeading(node)
2076 { if (!node || node.nodeType != 1)
2077 return null;
2078
2079 if (node.nodeName == "H1" || node.nodeName == "h1")
2080 return node;
2081
2082 var child = node.firstChild;
2083
2084 while (child)
2085 {
2086 node = findHeading(child);
2087
2088 if (node)
2089 return node;
2090
2091 child = child.nextSibling;
2092 }
2093
2094 return null;
2095 }
2096
2097 // recursively extract text from DOM tree
2098 function extractText(node)
2099 {
2100 if (!node)
2101 return "";
2102
2103 // text nodes
2104 if (node.nodeType == 3)
2105 return node.nodeValue;
2106
2107 // elements
2108 if (node.nodeType == 1)
2109 {
2110 node = node.firstChild;
2111 var text = "";
2112
2113 while (node)
2114 {
2115 text = text + extractText(node);
2116 node = node.nextSibling;
2117 }
2118
2119 return text;
2120 }
2121
2122 return "";
2123 }
2124
2125
2126 // find copyright text from meta element
2127 function findCopyright()
2128 {
2129 var name, content;
2130 var meta = document.getElementsByTagName("meta");
2131
2132 for (var i = 0; i < meta.length; ++i)
2133 {
2134 name = meta[i].getAttribute("name");
2135 content = meta[i].getAttribute("content");
2136
2137 if (name == "copyright")
2138 return content;
2139 }
2140
2141 return null;
2142 }
2143
2144 function findSizeAdjust()
2145 {
2146 var name, content, offset;
2147 var meta = document.getElementsByTagName("meta");
2148
2149 for (var i = 0; i < meta.length; ++i)
2150 {
2151 name = meta[i].getAttribute("name");
2152 content = meta[i].getAttribute("content");
2153
2154 if (name == "font-size-adjustment")
2155 return 1 * content;
2156 }
2157
2158 return 1;
2159 }
2160
2161 function addToolbar()
2162 {
2163 var slideCounter, page;
2164
2165 var toolbar = createElement("div");
2166 toolbar.setAttribute("class", "toolbar");
2167
2168 if (ns_pos) // a reasonably behaved browser
2169 {
2170 var right = document.createElement("div");
2171 right.setAttribute("style", "float: right; text-align: right");
2172
2173 slideCounter = document.createElement("div")
2174 slideCounter.innerHTML = "slide".localize() + " n/m";
2175 right.appendChild(slideCounter);
2176 toolbar.appendChild(right);
2177
2178 var left = document.createElement("div");
2179 left.setAttribute("style", "text-align: left");
2180
2181 // global end of slide indicator
2182 eos = document.createElement("span");
2183 eos.innerHTML = "* ";
2184 left.appendChild(eos);
2185
2186 var help = document.createElement("a");
2187 help.setAttribute("href", helpPage);
2188 help.setAttribute("title", helpText.localize());
2189 help.innerHTML = "help?".localize();
2190 left.appendChild(help);
2191 helpAnchor = help; // save for focus hack
2192
2193 var gap1 = document.createTextNode(" ");
2194 left.appendChild(gap1);
2195
2196 var contents = document.createElement("a");
2197 contents.setAttribute("href", "javascript:toggleTableOfContents()");
2198 contents.setAttribute("title", "table of contents".localize());
2199 contents.innerHTML = "contents?".localize();
2200 left.appendChild(contents);
2201
2202 var gap2 = document.createTextNode(" ");
2203 left.appendChild(gap2);
2204
2205 var start = document.createElement("a");
2206 start.setAttribute("href", "javascript:firstSlide()");
2207 start.setAttribute("title", "restart presentation".localize());
2208 start.innerHTML = "restart?".localize();
2209 // start.setAttribute("href", "javascript:printSlides()");
2210 // start.setAttribute("title", "print all slides".localize());
2211 // start.innerHTML = "print!".localize();
2212 left.appendChild(start);
2213
2214 var copyright = findCopyright();
2215
2216 if (copyright)
2217 {
2218 var span = document.createElement("span");
2219 span.innerHTML = copyright;
2220 span.style.color = "black";
2221 span.style.marginLeft = "4em";
2222 left.appendChild(span);
2223 }
2224
2225 toolbar.appendChild(left);
2226 }
2227 else // IE so need to work around its poor CSS support
2228 {
2229 toolbar.style.position = (ie7 ? "fixed" : "absolute");
2230 toolbar.style.zIndex = "200";
2231 toolbar.style.width = "99.9%";
2232 toolbar.style.height = "1.2em";
2233 toolbar.style.top = "auto";
2234 toolbar.style.bottom = "0";
2235 toolbar.style.left = "0";
2236 toolbar.style.right = "0";
2237 toolbar.style.textAlign = "left";
2238 toolbar.style.fontSize = "60%";
2239 toolbar.style.color = "red";
2240 toolbar.borderWidth = 0;
2241 toolbar.className = "toolbar";
2242 toolbar.style.background = "rgb(240,240,240)";
2243
2244 // would like to have help text left aligned
2245 // and page counter right aligned, floating
2246 // div's don't work, so instead use nested
2247 // absolutely positioned div's.
2248
2249 var sp = document.createElement("span");
2250 sp.innerHTML = "&nbsp;&nbsp;*&nbsp;";
2251 toolbar.appendChild(sp);
2252 eos = sp; // end of slide indicator
2253
2254 var help = document.createElement("a");
2255 help.setAttribute("href", helpPage);
2256 help.setAttribute("title", helpText.localize());
2257 help.innerHTML = "help?".localize();
2258 toolbar.appendChild(help);
2259 helpAnchor = help; // save for focus hack
2260
2261 var gap1 = document.createTextNode(" ");
2262 toolbar.appendChild(gap1);
2263
2264 var contents = document.createElement("a");
2265 contents.setAttribute("href", "javascript:toggleTableOfContents()");
2266 contents.setAttribute("title", "table of contents".localize());
2267 contents.innerHTML = "contents?".localize();
2268 toolbar.appendChild(contents);
2269
2270 var gap2 = document.createTextNode(" ");
2271 toolbar.appendChild(gap2);
2272
2273 var start = document.createElement("a");
2274 start.setAttribute("href", "javascript:firstSlide()");
2275 start.setAttribute("title", "restart presentation".localize());
2276 start.innerHTML = "restart?".localize();
2277 // start.setAttribute("href", "javascript:printSlides()");
2278 // start.setAttribute("title", "print all slides".localize());
2279 // start.innerHTML = "print!".localize();
2280 toolbar.appendChild(start);
2281
2282 var copyright = findCopyright();
2283
2284 if (copyright)
2285 {
2286 var span = document.createElement("span");
2287 span.innerHTML = copyright;
2288 span.style.color = "black";
2289 span.style.marginLeft = "2em";
2290 toolbar.appendChild(span);
2291 }
2292
2293 slideCounter = document.createElement("div")
2294 slideCounter.style.position = "absolute";
2295 slideCounter.style.width = "auto"; //"20%";
2296 slideCounter.style.height = "1.2em";
2297 slideCounter.style.top = "auto";
2298 slideCounter.style.bottom = 0;
2299 slideCounter.style.right = "0";
2300 slideCounter.style.textAlign = "right";
2301 slideCounter.style.color = "red";
2302 slideCounter.style.background = "rgb(240,240,240)";
2303
2304 slideCounter.innerHTML = "slide".localize() + " n/m";
2305 toolbar.appendChild(slideCounter);
2306 }
2307
2308 // ensure that click isn't passed through to the page
2309 toolbar.onclick = stopPropagation;
2310 document.body.appendChild(toolbar);
2311 slideNumElement = slideCounter;
2312 setEosStatus(false);
2313
2314 return toolbar;
2315 }
2316
2317 function isShownToc()
2318 {
2319 if (toc && toc.style.visible == "visible")
2320 return true;
2321
2322 return false;
2323 }
2324
2325 function showTableOfContents()
2326 {
2327 if (toc)
2328 {
2329 if (toc.style.visibility != "visible")
2330 {
2331 toc.style.visibility = "visible";
2332 toc.style.display = "block";
2333 toc.focus();
2334
2335 if (ie7 && slidenum == 0)
2336 setTimeout("ieHack()", 100);
2337 }
2338 else
2339 hideTableOfContents();
2340 }
2341 }
2342
2343 function hideTableOfContents()
2344 {
2345 if (toc && toc.style.visibility != "hidden")
2346 {
2347 toc.style.visibility = "hidden";
2348 toc.style.display = "none";
2349
2350 try
2351 {
2352 if (!opera)
2353 helpAnchor.focus();
2354 }
2355 catch (e)
2356 {
2357 }
2358 }
2359 }
2360
2361 function toggleTableOfContents()
2362 {
2363 if (toc)
2364 {
2365 if (toc.style.visible != "visible")
2366 showTableOfContents();
2367 else
2368 hideTableOfContents();
2369 }
2370 }
2371
2372 // called on clicking toc entry
2373 function gotoEntry(e)
2374 {
2375 var target;
2376
2377 if (!e)
2378 var e = window.event;
2379
2380 if (e.target)
2381 target = e.target;
2382 else if (e.srcElement)
2383 target = e.srcElement;
2384
2385 // work around Safari bug
2386 if (target.nodeType == 3)
2387 target = target.parentNode;
2388
2389 if (target && target.nodeType == 1)
2390 {
2391 var uri = target.getAttribute("href");
2392
2393 if (uri)
2394 {
2395 //alert("going to " + uri);
2396 var slide = slides[slidenum];
2397 hideSlide(slide);
2398 slidenum = findSlideNumber(uri);
2399 slide = slides[slidenum];
2400 lastShown = null;
2401 setLocation();
2402 setVisibilityAllIncremental("hidden");
2403 setEosStatus(!nextIncrementalItem(lastShown));
2404 showSlide(slide);
2405 //target.focus();
2406
2407 try
2408 {
2409 if (!opera)
2410 helpAnchor.focus();
2411 }
2412 catch (e)
2413 {
2414 }
2415 }
2416 }
2417
2418 hideTableOfContents(e);
2419 if (ie7) ieHack();
2420 stopPropagation(e);
2421 return cancel(e);
2422 }
2423
2424 // called onkeydown for toc entry
2425 function gotoTocEntry(event)
2426 {
2427 var key;
2428
2429 if (!event)
2430 var event = window.event;
2431
2432 // kludge around NS/IE differences
2433 if (window.event)
2434 key = window.event.keyCode;
2435 else if (event.which)
2436 key = event.which;
2437 else
2438 return true; // Yikes! unknown browser
2439
2440 // ignore event if key value is zero
2441 // as for alt on Opera and Konqueror
2442 if (!key)
2443 return true;
2444
2445 // check for concurrent control/command/alt key
2446 // but are these only present on mouse events?
2447
2448 if (event.ctrlKey || event.altKey)
2449 return true;
2450
2451 if (key == 13)
2452 {
2453 var uri = this.getAttribute("href");
2454
2455 if (uri)
2456 {
2457 //alert("going to " + uri);
2458 var slide = slides[slidenum];
2459 hideSlide(slide);
2460 slidenum = findSlideNumber(uri);
2461 slide = slides[slidenum];
2462 lastShown = null;
2463 setLocation();
2464 setVisibilityAllIncremental("hidden");
2465 setEosStatus(!nextIncrementalItem(lastShown));
2466 showSlide(slide);
2467 //target.focus();
2468
2469 try
2470 {
2471 if (!opera)
2472 helpAnchor.focus();
2473 }
2474 catch (e)
2475 {
2476 }
2477 }
2478
2479 hideTableOfContents();
2480 if (ie7) ieHack();
2481 return cancel(event);
2482 }
2483
2484 if (key == 40 && this.next)
2485 {
2486 this.next.focus();
2487 return cancel(event);
2488 }
2489
2490 if (key == 38 && this.previous)
2491 {
2492 this.previous.focus();
2493 return cancel(event);
2494 }
2495
2496 return true;
2497 }
2498
2499 function isTitleSlide(slide)
2500 {
2501 return hasClass(slide, "title");
2502 }
2503
2504 // create div element with links to each slide
2505 function tableOfContents()
2506 {
2507 var toc = document.createElement("div");
2508 addClass(toc, "toc");
2509 //toc.setAttribute("tabindex", "0");
2510
2511 var heading = document.createElement("div");
2512 addClass(heading, "toc-heading");
2513 heading.innerHTML = "Table of Contents".localize();
2514
2515 heading.style.textAlign = "center";
2516 heading.style.width = "100%";
2517 heading.style.margin = "0";
2518 heading.style.marginBottom = "1em";
2519 heading.style.borderBottomStyle = "solid";
2520 heading.style.borderBottomColor = "rgb(180,180,180)";
2521 heading.style.borderBottomWidth = "1px";
2522
2523 toc.appendChild(heading);
2524 var previous = null;
2525
2526 for (var i = 0; i < slides.length; ++i)
2527 {
2528 var title = hasClass(slides[i], "title");
2529 var num = document.createTextNode((i + 1) + ". ");
2530
2531 toc.appendChild(num);
2532
2533 var a = document.createElement("a");
2534 a.setAttribute("href", "#(" + (i+1) + ")");
2535
2536 if (title)
2537 addClass(a, "titleslide");
2538
2539 var name = document.createTextNode(slideName(i));
2540 a.appendChild(name);
2541 a.onclick = gotoEntry;
2542 a.onkeydown = gotoTocEntry;
2543 a.previous = previous;
2544
2545 if (previous)
2546 previous.next = a;
2547
2548 toc.appendChild(a);
2549
2550 if (i == 0)
2551 toc.first = a;
2552
2553 if (i < slides.length - 1)
2554 {
2555 var br = document.createElement("br");
2556 toc.appendChild(br);
2557 }
2558
2559 previous = a;
2560 }
2561
2562 toc.focus = function () {
2563 if (this.first)
2564 this.first.focus();
2565 }
2566
2567 toc.onmouseup = mouseButtonUp;
2568
2569 toc.onclick = function (e) {
2570 e||(e=window.event);
2571
2572 if (selectedTextLen <= 0)
2573 hideTableOfContents();
2574
2575 stopPropagation(e);
2576
2577 if (e.cancel != undefined)
2578 e.cancel = true;
2579
2580 if (e.returnValue != undefined)
2581 e.returnValue = false;
2582
2583 return false;
2584 };
2585
2586 toc.style.position = "absolute";
2587 toc.style.zIndex = "300";
2588 toc.style.width = "60%";
2589 toc.style.maxWidth = "30em";
2590 toc.style.height = "30em";
2591 toc.style.overflow = "auto";
2592 toc.style.top = "auto";
2593 toc.style.right = "auto";
2594 toc.style.left = "4em";
2595 toc.style.bottom = "4em";
2596 toc.style.padding = "1em";
2597 toc.style.background = "rgb(240,240,240)";
2598 toc.style.borderStyle = "solid";
2599 toc.style.borderWidth = "2px";
2600 toc.style.fontSize = "60%";
2601
2602 document.body.insertBefore(toc, document.body.firstChild);
2603 return toc;
2604 }
2605
2606 function replaceByNonBreakingSpace(str)
2607 {
2608 for (var i = 0; i < str.length; ++i)
2609 str[i] = 160;
2610 }
2611
2612
2613 function initOutliner()
2614 {
2615 var items = document.getElementsByTagName("LI");
2616
2617 for (var i = 0; i < items.length; ++i)
2618 {
2619 var target = items[i];
2620
2621 if (!hasClass(target.parentNode, "outline"))
2622 continue;
2623
2624 target.onclick = outlineClick;
2625
2626 if (!ns_pos)
2627 {
2628 target.onmouseover = hoverOutline;
2629 target.onmouseout = unhoverOutline;
2630 }
2631
2632 if (foldable(target))
2633 {
2634 target.foldable = true;
2635 target.onfocus = function () {outline = this;};
2636 target.onblur = function () {outline = null;};
2637
2638 if (!target.getAttribute("tabindex"))
2639 target.setAttribute("tabindex", "0");
2640
2641 if (hasClass(target, "expand"))
2642 unfold(target);
2643 else
2644 fold(target);
2645 }
2646 else
2647 {
2648 addClass(target, "nofold");
2649 target.visible = true;
2650 target.foldable = false;
2651 }
2652 }
2653 }
2654
2655 function foldable(item)
2656 {
2657 if (!item || item.nodeType != 1)
2658 return false;
2659
2660 var node = item.firstChild;
2661
2662 while (node)
2663 {
2664 if (node.nodeType == 1 && isBlock(node))
2665 return true;
2666
2667 node = node.nextSibling;
2668 }
2669
2670 return false;
2671 }
2672
2673 function fold(item)
2674 {
2675 if (item)
2676 {
2677 removeClass(item, "unfolded");
2678 addClass(item, "folded");
2679 }
2680
2681 var node = item ? item.firstChild : null;
2682
2683 while (node)
2684 {
2685 if (node.nodeType == 1 && isBlock(node)) // element
2686 {
2687 // note that getElementStyle won't work for Safari 1.3
2688 node.display = getElementStyle(node, "display", "display");
2689 node.style.display = "none";
2690 node.style.visibility = "hidden";
2691 }
2692
2693 node = node.nextSibling;
2694 }
2695
2696 item.visible = false;
2697 }
2698
2699 function unfold(item)
2700 {
2701 if (item)
2702 {
2703 addClass(item, "unfolded");
2704 removeClass(item, "folded");
2705 }
2706
2707 var node = item ? item.firstChild : null;
2708
2709 while (node)
2710 {
2711 if (node.nodeType == 1 && isBlock(node)) // element
2712 {
2713 // with fallback for Safari, see above
2714 node.style.display = (node.display ? node.display : "block");
2715 node.style.visibility = "visible";
2716 }
2717
2718 node = node.nextSibling;
2719 }
2720
2721 item.visible = true;
2722 }
2723
2724 function outlineClick(e)
2725 {
2726 var rightclick = false;
2727 var target;
2728
2729 if (!e)
2730 var e = window.event;
2731
2732 if (e.target)
2733 target = e.target;
2734 else if (e.srcElement)
2735 target = e.srcElement;
2736
2737 // work around Safari bug
2738 if (target.nodeType == 3)
2739 target = target.parentNode;
2740
2741 while (target && target.visible == undefined)
2742 target = target.parentNode;
2743
2744 if (!target)
2745 return true;
2746
2747 if (e.which)
2748 rightclick = (e.which == 3);
2749 else if (e.button)
2750 rightclick = (e.button == 2);
2751
2752 if (!rightclick && target.visible != undefined)
2753 {
2754 if (target.foldable)
2755 {
2756 if (target.visible)
2757 fold(target);
2758 else
2759 unfold(target);
2760 }
2761
2762 stopPropagation(e);
2763 e.cancel = true;
2764 e.returnValue = false;
2765 }
2766
2767 return false;
2768 }
2769
2770 function hoverOutline(e)
2771 {
2772 var target;
2773
2774 if (!e)
2775 var e = window.event;
2776
2777 if (e.target)
2778 target = e.target;
2779 else if (e.srcElement)
2780 target = e.srcElement;
2781
2782 // work around Safari bug
2783 if (target.nodeType == 3)
2784 target = target.parentNode;
2785
2786 while (target && target.visible == undefined)
2787 target = target.parentNode;
2788
2789 if (target && target.foldable)
2790 target.style.cursor = "pointer";
2791
2792 return true;
2793 }
2794
2795 function unhoverOutline(e)
2796 {
2797 var target;
2798
2799 if (!e)
2800 var e = window.event;
2801
2802 if (e.target)
2803 target = e.target;
2804 else if (e.srcElement)
2805 target = e.srcElement;
2806
2807 // work around Safari bug
2808 if (target.nodeType == 3)
2809 target = target.parentNode;
2810
2811 while (target && target.visible == undefined)
2812 target = target.parentNode;
2813
2814 if (target)
2815 target.style.cursor = "default";
2816
2817 return true;
2818 }
2819
2820
2821 function stopPropagation(e)
2822 {
2823 if (window.event)
2824 {
2825 window.event.cancelBubble = true;
2826 //window.event.returnValue = false;
2827 }
2828 else if (e)
2829 {
2830 e.cancelBubble = true;
2831 e.stopPropagation();
2832 //e.preventDefault();
2833 }
2834 }
2835
2836 /* can't rely on display since we set that to none to hide things */
2837 function isBlock(elem)
2838 {
2839 var tag = elem.nodeName;
2840
2841 return tag == "OL" || tag == "UL" || tag == "P" ||
2842 tag == "LI" || tag == "TABLE" || tag == "PRE" ||
2843 tag == "H1" || tag == "H2" || tag == "H3" ||
2844 tag == "H4" || tag == "H5" || tag == "H6" ||
2845 tag == "BLOCKQUOTE" || tag == "ADDRESS";
2846 }
2847
2848 function getElementStyle(elem, IEStyleProp, CSSStyleProp)
2849 {
2850 if (elem.currentStyle)
2851 {
2852 return elem.currentStyle[IEStyleProp];
2853 }
2854 else if (window.getComputedStyle)
2855 {
2856 var compStyle = window.getComputedStyle(elem, "");
2857 return compStyle.getPropertyValue(CSSStyleProp);
2858 }
2859 return "";
2860 }
2861
2862 // works with text/html and text/xhtml+xml with thanks to Simon Willison
2863 function createElement(element)
2864 {
2865 if (typeof document.createElementNS != 'undefined')
2866 {
2867 return document.createElementNS('http://www.w3.org/1999/xhtml', element);
2868 }
2869
2870 if (typeof document.createElement != 'undefined')
2871 {
2872 return document.createElement(element);
2873 }
2874
2875 return false;
2876 }
2877
2878 // designed to work with both text/html and text/xhtml+xml
2879 function getElementsByTagName(name)
2880 {
2881 if (typeof document.getElementsByTagNameNS != 'undefined')
2882 {
2883 return document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', name);
2884 }
2885
2886 if (typeof document.getElementsByTagName != 'undefined')
2887 {
2888 return document.getElementsByTagName(name);
2889 }
2890
2891 return null;
2892 }
2893
2894 /*
2895 // clean alternative to innerHTML method, but on IE6
2896 // it doesn't work with named entities like &nbsp;
2897 // which need to be replaced by numeric entities
2898 function insertText(element, text)
2899 {
2900 try
2901 {
2902 element.textContent = text; // DOM3 only
2903 }
2904 catch (e)
2905 {
2906 if (element.firstChild)
2907 {
2908 // remove current children
2909 while (element.firstChild)
2910 element.removeChild(element.firstChild);
2911 }
2912
2913 element.appendChild(document.createTextNode(text));
2914 }
2915 }
2916
2917 // as above, but as method of all element nodes
2918 // doesn't work in IE6 which doesn't allow you to
2919 // add methods to the HTMLElement prototype
2920 if (HTMLElement != undefined)
2921 {
2922 HTMLElement.prototype.insertText = function(text) {
2923 var element = this;
2924
2925 try
2926 {
2927 element.textContent = text; // DOM3 only
2928 }
2929 catch (e)
2930 {
2931 if (element.firstChild)
2932 {
2933 // remove current children
2934 while (element.firstChild)
2935 element.removeChild(element.firstChild);
2936 }
2937
2938 element.appendChild(document.createTextNode(text));
2939 }
2940 };
2941 }
2942 */
2943
2944 function getSelectedText()
2945 {
2946 try
2947 {
2948 if (window.getSelection)
2949 return window.getSelection().toString();
2950
2951 if (document.getSelection)
2952 return document.getSelection().toString();
2953
2954 if (document.selection)
2955 return document.selection.createRange().text;
2956 }
2957 catch (e)
2958 {
2959 return "";
2960 }
2961 return "";
2962 }