comparison recital-slide/slidy.js @ 15:67544736317e

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