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