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