Mercurial > hg > Papers > 2010 > kent-master
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, "&"); | |
2055 name.replace(/\</g, "<"); | |
2056 name.replace(/\>/g, ">"); | |
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 = " * "; | |
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 | |
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 |