--- /dev/null
+/* http://www.w3.org/Talks/Tools/Slidy/slidy.js
+
+ Copyright (c) 2005 W3C (MIT, ERCIM, Keio), All Rights Reserved.
+ W3C liability, trademark, document use and software licensing
+ rules apply, see:
+
+ http://www.w3.org/Consortium/Legal/copyright-documents
+ http://www.w3.org/Consortium/Legal/copyright-software
+*/
+
+var ns_pos = (typeof window.pageYOffset!='undefined');
+var khtml = ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false);
+var opera = ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false);
+var ie7 = (!ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1);
+
+window.onload = startup; // equivalent to onload on body element
+
+// IE only event handlers to ensure all slides are printed
+// I don't yet know how to emulate these for other browsers
+window.onbeforeprint = beforePrint;
+window.onafterprint = afterPrint;
+
+// hack to hide slides while loading
+setTimeout(hideAll, 50);
+
+function hideAll()
+{
+ if (document.body)
+ document.body.style.visibility = "hidden";
+ else
+ setTimeout(hideAll, 50);
+}
+
+var slidenum = 0; // integer slide count: 0, 1, 2, ...
+var slides; // set to array of slide div's
+var slideNumElement; // element containing slide number
+var notes; // set to array of handout div's
+var backgrounds; // set to array of background div's
+var toolbar; // element containing toolbar
+var title; // document title
+var lastShown = null; // last incrementally shown item
+var eos = null; // span element for end of slide indicator
+var toc = null; // table of contents
+var outline = null; // outline element with the focus
+var selectedTextLen; // length of drag selection on document
+
+var viewAll = 0; // 1 to view all slides + handouts
+var wantToolbar = 1; // 0 if toolbar isn't wanted
+var mouseClickEnabled = true; // enables left click for next slide
+var scrollhack = 0; // IE work around for position: fixed
+
+var helpAnchor; // used for keyboard focus hack in showToolbar()
+var helpPage = "http://www.w3.org/Talks/Tools/Slidy/help.html";
+var helpText = "Navigate with mouse click, space bar, Cursor Left/Right, " +
+ "or Pg Up and Pg Dn. Use S and B to change font size.";
+
+var sizeIndex = 0;
+var sizeAdjustment = 0;
+var sizes = new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
+ "22pt", "24pt", "26pt", "28pt", "30pt", "32pt");
+
+var okayForIncremental = incrementalElementList();
+
+// needed for efficient resizing
+var lastWidth = 0;
+var lastHeight = 0;
+
+// Needed for cross browser support for relative width/height on
+// object elements. The work around is to save width/height attributes
+// and then to recompute absolute width/height dimensions on resizing
+var objects;
+
+// updated to language specified by html file
+var lang = "en";
+
+//var localize = {};
+
+// for each language there is an associative array
+var strings_es = {
+ "slide":"pág.",
+ "help?":"Ayuda",
+ "contents?":"Índice",
+ "table of contents":"tabla de contenidos",
+ "Table of Contents":"Tabla de Contenidos",
+ "restart presentation":"Reiniciar presentación",
+ "restart?":"Inicio"
+ };
+
+strings_es[helpText] =
+ "Utilice el ratón, barra espaciadora, teclas Izda/Dhca, " +
+ "o Re pág y Av pág. Use S y B para cambiar el tamaño de fuente.";
+
+var strings_nl = {
+ "slide":"pagina",
+ "help?":"Help?",
+ "contents?":"Inhoud?",
+ "table of contents":"inhoudsopgave",
+ "Table of Contents":"Inhoudsopgave",
+ "restart presentation":"herstart presentatie",
+ "restart?":"Herstart?"
+ };
+
+strings_nl[helpText] =
+ "Navigeer d.m.v. het muis, spatiebar, Links/Rechts toetsen, " +
+ "of PgUp en PgDn. Gebruik S en B om de karaktergrootte te veranderen.";
+
+var strings_de = {
+ "slide":"Seite",
+ "help?":"Hilfe",
+ "contents?":"Übersicht",
+ "table of contents":"Inhaltsverzeichnis",
+ "Table of Contents":"Inhaltsverzeichnis",
+ "restart presentation":"Präsentation neu starten",
+ "restart?":"Neustart"
+ };
+
+strings_de[helpText] =
+ "Benutzen Sie die Maus, Leerschlag, die Cursortasten links/rechts" +
+ "oder Page up/Page Down zum Wechseln der Seiten und S und B für die Schriftgrösse.";
+
+var strings_pl = {
+ "slide":"slajd",
+ "help?":"pomoc?",
+ "contents?":"spis treści?",
+ "table of contents":"spis treści",
+ "Table of Contents":"Spis Treści",
+ "restart presentation":"Restartuj prezentację",
+ "restart?":"restart?"
+ };
+
+strings_pl[helpText] =
+ "Zmieniaj slajdy klikając myszą, naciskając spację, strzałki lewo/prawo" +
+ "lub PgUp / PgDn. Użyj klawiszy S i B, aby zmienić rozmiar czczionki.";
+
+var strings_fr = {
+ "slide":"page",
+ "help?":"Aide",
+ "contents?":"Index",
+ "table of contents":"table des matières",
+ "Table of Contents":"Table des matières",
+ "restart presentation":"Recommencer l'exposé",
+ "restart?":"Début"
+ };
+
+strings_fr[helpText] =
+ "Naviguez avec la souris, la barre d'espace, les flèches" +
+ "gauche/droite ou les touches Pg Up, Pg Dn. Utilisez " +
+ "les touches S et B pour modifier la taille de la police.";
+
+var strings_hu = {
+ "slide":"oldal",
+ "help?":"segítség",
+ "contents?":"tartalom",
+ "table of contents":"tartalomjegyzék",
+ "Table of Contents":"Tartalomjegyzék",
+ "restart presentation":"bemutató újraindítása",
+ "restart?":"újraindítás"
+ };
+
+strings_hu[helpText] =
+ "Az oldalak közti lépkedéshez kattintson az egérrel, vagy használja a szóköz, a bal, vagy a jobb nyíl, " +
+ "illetve a Page Down, Page Up billentyűket. Az S és a B billentyűkkel változtathatja a szöveg méretét.";
+
+var strings_it = {
+ "slide":"pag.",
+ "help?":"Aiuto",
+ "contents?":"Indice",
+ "table of contents":"indice",
+ "Table of Contents":"Indice",
+ "restart presentation":"Ricominciare la presentazione",
+ "restart?":"Inizio"
+ };
+
+strings_it[helpText] =
+ "Navigare con mouse, barra spazio, frecce sinistra/destra o " +
+ "PgUp e PgDn. Usare S e B per cambiare la dimensione dei caratteri.";
+
+var strings_el = {
+ "slide":"σελίδα",
+ "help?":"βοήθεια;",
+ "contents?":"περιεχόμενα;",
+ "table of contents":"πίνακας περιεχομένων",
+ "Table of Contents":"Πίνακας Περιεχομένων",
+ "restart presentation":"επανεκκίνηση παρουσίασης",
+ "restart?":"επανεκκίνηση;"
+ };
+
+strings_el[helpText] =
+ "Πλοηγηθείτε με το κλίκ του ποντικιού, το space, τα βέλη αριστερά/δεξιά, " +
+ "ή Page Up και Page Down. Χρησιμοποιήστε τα πλήκτρα S και B για να αλλάξετε " +
+ "το μέγεθος της γραμματοσειράς.";
+
+var strings_ja = {
+ "slide":"スライド",
+ "help?":"ヘルプ",
+ "contents?":"目次",
+ "table of contents":"目次を表示",
+ "Table of Contents":"目次",
+ "restart presentation":"最初から再生",
+ "restart?":"最初から"
+};
+
+strings_ja[helpText] =
+ "マウス左クリック ・ スペース ・ 左右キー " +
+ "または Page Up ・ Page Downで操作, S ・ Bでフォントサイズ変更";
+
+
+// each such language array is declared in the localize array
+// used indirectly as in help.innerHTML = "help".localize();
+var localize = {
+ "es":strings_es,
+ "nl":strings_nl,
+ "de":strings_de,
+ "pl":strings_pl,
+ "fr":strings_fr,
+ "hu":strings_hu,
+ "it":strings_it,
+ "el":strings_el,
+ "jp":strings_ja
+ };
+
+/* general initialization */
+function startup()
+{
+ // find human language from html element
+ // for use in localizing strings
+ lang = document.body.parentNode.getAttribute("lang");
+
+ if (!lang)
+ lang = document.body.parentNode.getAttribute("xml:lang");
+
+ if (!lang)
+ lang = "en";
+
+ document.body.style.visibility = "visible";
+ title = document.title;
+ toolbar = addToolbar();
+ wrapImplicitSlides();
+ slides = collectSlides();
+ notes = collectNotes();
+ objects = document.body.getElementsByTagName("object");
+ backgrounds = collectBackgrounds();
+ patchAnchors();
+
+ slidenum = findSlideNumber(location.href);
+ window.offscreenbuffering = true;
+ sizeAdjustment = findSizeAdjust();
+ hideImageToolbar(); // suppress IE image toolbar popup
+ initOutliner(); // activate fold/unfold support
+
+ if (slides.length > 0)
+ {
+ var slide = slides[slidenum];
+ slide.style.position = "absolute";
+
+ if (slidenum > 0)
+ {
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ setEosStatus(true);
+ }
+ else
+ {
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ }
+
+ setLocation();
+ }
+
+ toc = tableOfContents();
+ hideTableOfContents();
+
+ // bind event handlers
+ document.onclick = mouseButtonClick;
+ document.onmouseup = mouseButtonUp;
+ document.onkeydown = keyDown;
+ window.onresize = resized;
+ window.onscroll = scrolled;
+ singleSlideView();
+
+ setLocation();
+ resized();
+
+ if (ie7)
+ setTimeout("ieHack()", 100);
+
+ showToolbar();
+}
+
+// add localize method to all strings for use
+// as in help.innerHTML = "help".localize();
+String.prototype.localize = function()
+{
+ if (this == "")
+ return this;
+
+ // try full language code, e.g. en-US
+ var s, lookup = localize[lang];
+
+ if (lookup)
+ {
+ s = lookup[this];
+
+ if (s)
+ return s;
+ }
+
+ // try en if undefined for en-US
+ var lg = lang.split("-");
+
+ if (lg.length > 1)
+ {
+ lookup = localize[lg[0]];
+
+ if (lookup)
+ {
+ s = lookup[this];
+
+ if (s)
+ return s;
+ }
+ }
+
+ // otherwise string as is
+ return this;
+}
+
+// suppress IE's image toolbar pop up
+function hideImageToolbar()
+{
+ if (!ns_pos)
+ {
+ var images = document.getElementsByTagName("IMG");
+
+ for (var i = 0; i < images.length; ++i)
+ images[i].setAttribute("galleryimg", "no");
+ }
+}
+
+// hack to persuade IE to compute correct document height
+// as needed for simulating fixed positioning of toolbar
+function ieHack()
+{
+ window.resizeBy(0,-1);
+ window.resizeBy(0, 1);
+}
+
+// Firefox reload SVG bug work around
+function reload(e)
+{
+ if (!e)
+ var e = window.event;
+
+ hideBackgrounds();
+ setTimeout("document.reload();", 100);
+
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+
+ return false;
+}
+
+// Safari and Konqueror don't yet support getComputedStyle()
+// and they always reload page when location.href is updated
+function isKHTML()
+{
+ var agent = navigator.userAgent;
+ return (agent.indexOf("KHTML") >= 0 ? true : false);
+}
+
+function resized()
+{
+ var width = 0;
+
+ if ( typeof( window.innerWidth ) == 'number' )
+ width = window.innerWidth; // Non IE browser
+ else if (document.documentElement && document.documentElement.clientWidth)
+ width = document.documentElement.clientWidth; // IE6
+ else if (document.body && document.body.clientWidth)
+ width = document.body.clientWidth; // IE4
+
+ var height = 0;
+
+ if ( typeof( window.innerHeight ) == 'number' )
+ height = window.innerHeight; // Non IE browser
+ else if (document.documentElement && document.documentElement.clientHeight)
+ height = document.documentElement.clientHeight; // IE6
+ else if (document.body && document.body.clientHeight)
+ height = document.body.clientHeight; // IE4
+
+ if (height && (width/height > 1.05*1024/768))
+ {
+ width = height * 1024.0/768;
+ }
+
+ // IE fires onresize even when only font size is changed!
+ // so we do a check to avoid blocking < and > actions
+ if (width != lastWidth || height != lastHeight)
+ {
+ if (width >= 1100)
+ sizeIndex = 5; // 4
+ else if (width >= 1000)
+ sizeIndex = 4; // 3
+ else if (width >= 800)
+ sizeIndex = 3; // 2
+ else if (width >= 600)
+ sizeIndex = 2; // 1
+ else if (width)
+ sizeIndex = 0;
+
+ // add in font size adjustment from meta element e.g.
+ // <meta name="font-size-adjustment" content="-2" />
+ // useful when slides have too much content ;-)
+
+ if (0 <= sizeIndex + sizeAdjustment &&
+ sizeIndex + sizeAdjustment < sizes.length)
+ sizeIndex = sizeIndex + sizeAdjustment;
+
+ // enables cross browser use of relative width/height
+ // on object elements for use with SVG and Flash media
+ adjustObjectDimensions(width, height);
+
+ document.body.style.fontSize = sizes[sizeIndex];
+
+ lastWidth = width;
+ lastHeight = height;
+
+ // force reflow to work around Mozilla bug
+ //if (ns_pos)
+ {
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ }
+
+ // force correct positioning of toolbar
+ refreshToolbar(200);
+ }
+}
+
+function scrolled()
+{
+ if (toolbar && !ns_pos && !ie7)
+ {
+ hackoffset = scrollXOffset();
+ // hide toolbar
+ toolbar.style.display = "none";
+
+ // make it reappear later
+ if (scrollhack == 0 && !viewAll)
+ {
+ setTimeout(showToolbar, 1000);
+ scrollhack = 1;
+ }
+ }
+}
+
+// used to ensure IE refreshes toolbar in correct position
+function refreshToolbar(interval)
+{
+ if (!ns_pos && !ie7)
+ {
+ hideToolbar();
+ setTimeout(showToolbar, interval);
+ }
+}
+
+// restores toolbar after short delay
+function showToolbar()
+{
+ if (wantToolbar)
+ {
+ if (!ns_pos)
+ {
+ // adjust position to allow for scrolling
+ var xoffset = scrollXOffset();
+ toolbar.style.left = xoffset;
+ toolbar.style.right = xoffset;
+
+ // determine vertical scroll offset
+ //var yoffset = scrollYOffset();
+
+ // bottom is doc height - window height - scroll offset
+ //var bottom = documentHeight() - lastHeight - yoffset
+
+ //if (yoffset > 0 || documentHeight() > lastHeight)
+ // bottom += 16; // allow for height of scrollbar
+
+ toolbar.style.bottom = 0; //bottom;
+ }
+
+ toolbar.style.display = "block";
+ toolbar.style.visibility = "visible";
+ }
+
+ scrollhack = 0;
+
+
+ // set the keyboard focus to the help link on the
+ // toolbar to ensure that document has the focus
+ // IE doesn't always work with window.focus()
+ // and this hack has benefit of Enter for help
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+}
+
+function test()
+{
+ var s = "docH: " + documentHeight() +
+ " winH: " + lastHeight +
+ " yoffset: " + scrollYOffset() +
+ " toolbot: " + (documentHeight() - lastHeight - scrollYOffset());
+
+ //alert(s);
+
+ var slide = slides[slidenum];
+ // IE getAttribute requires "class" to be "className"
+ var name = ns_pos ? "class" : "className";
+ var style = (slide.currentStyle ? slide.currentStyle["backgroundColor"] :
+ document.defaultView.getComputedStyle(slide, '').getPropertyValue("background-color"));
+ alert("class='" + slide.getAttribute(name) + "' backgroundColor: " + style);
+}
+
+function hideToolbar()
+{
+ toolbar.style.display = "none";
+ toolbar.style.visibility = "hidden";
+ window.focus();
+}
+
+// invoked via F key
+function toggleToolbar()
+{
+ if (!viewAll)
+ {
+ if (toolbar.style.display == "none")
+ {
+ toolbar.style.display = "block";
+ toolbar.style.visibility = "visible";
+ wantToolbar = 1;
+ }
+ else
+ {
+ toolbar.style.display = "none";
+ toolbar.style.visibility = "hidden";
+ wantToolbar = 0;
+ }
+ }
+}
+
+function scrollXOffset()
+{
+ if (window.pageXOffset)
+ return self.pageXOffset;
+
+ if (document.documentElement &&
+ document.documentElement.scrollLeft)
+ return document.documentElement.scrollLeft;
+
+ if (document.body)
+ return document.body.scrollLeft;
+
+ return 0;
+}
+
+
+function scrollYOffset()
+{
+ if (window.pageYOffset)
+ return self.pageYOffset;
+
+ if (document.documentElement &&
+ document.documentElement.scrollTop)
+ return document.documentElement.scrollTop;
+
+ if (document.body)
+ return document.body.scrollTop;
+
+ return 0;
+}
+
+// looking for a way to determine height of slide content
+// the slide itself is set to the height of the window
+function optimizeFontSize()
+{
+ var slide = slides[slidenum];
+
+ //var dh = documentHeight(); //getDocHeight(document);
+ var dh = slide.scrollHeight;
+ var wh = getWindowHeight();
+ var u = 100 * dh / wh;
+
+ alert("window utilization = " + u + "% (doc "
+ + dh + " win " + wh + ")");
+}
+
+function getDocHeight(doc) // from document object
+{
+ if (!doc)
+ doc = document;
+
+ if (doc && doc.body && doc.body.offsetHeight)
+ return doc.body.offsetHeight; // ns/gecko syntax
+
+ if (doc && doc.body && doc.body.scrollHeight)
+ return doc.body.scrollHeight;
+
+ alert("couldn't determine document height");
+}
+
+function getWindowHeight()
+{
+ if ( typeof( window.innerHeight ) == 'number' )
+ return window.innerHeight; // Non IE browser
+
+ if (document.documentElement && document.documentElement.clientHeight)
+ return document.documentElement.clientHeight; // IE6
+
+ if (document.body && document.body.clientHeight)
+ return document.body.clientHeight; // IE4
+}
+
+
+
+function documentHeight()
+{
+ var sh, oh;
+
+ sh = document.body.scrollHeight;
+ oh = document.body.offsetHeight;
+
+ if (sh && oh)
+ {
+ return (sh > oh ? sh : oh);
+ }
+
+ // no idea!
+ return 0;
+}
+
+function smaller()
+{
+ if (sizeIndex > 0)
+ {
+ --sizeIndex;
+ }
+
+ toolbar.style.display = "none";
+ document.body.style.fontSize = sizes[sizeIndex];
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ setTimeout(showToolbar, 300);
+}
+
+function bigger()
+{
+ if (sizeIndex < sizes.length - 1)
+ {
+ ++sizeIndex;
+ }
+
+ toolbar.style.display = "none";
+ document.body.style.fontSize = sizes[sizeIndex];
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ showSlide(slide);
+ setTimeout(showToolbar, 300);
+}
+
+// enables cross browser use of relative width/height
+// on object elements for use with SVG and Flash media
+// with thanks to Ivan Herman for the suggestion
+function adjustObjectDimensions(width, height)
+{
+ for( var i = 0; i < objects.length; i++ )
+ {
+ var obj = objects[i];
+ var mimeType = obj.getAttribute("type");
+
+ if (mimeType == "image/svg+xml" || mimeType == "application/x-shockwave-flash")
+ {
+ if ( !obj.initialWidth )
+ obj.initialWidth = obj.getAttribute("width");
+
+ if ( !obj.initialHeight )
+ obj.initialHeight = obj.getAttribute("height");
+
+ if ( obj.initialWidth && obj.initialWidth.charAt(obj.initialWidth.length-1) == "%" )
+ {
+ var w = parseInt(obj.initialWidth.slice(0, obj.initialWidth.length-1));
+ var newW = width * (w/100.0);
+ obj.setAttribute("width",newW);
+ }
+
+ if ( obj.initialHeight && obj.initialHeight.charAt(obj.initialHeight.length-1) == "%" )
+ {
+ var h = parseInt(obj.initialHeight.slice(0, obj.initialHeight.length-1));
+ var newH = height * (h/100.0);
+ obj.setAttribute("height", newH);
+ }
+ }
+ }
+}
+
+function cancel(event)
+{
+ if (event)
+ {
+ event.cancel = true;
+ event.returnValue = false;
+
+ if (event.preventDefault)
+ event.preventDefault();
+ }
+
+ return false;
+}
+
+// See e.g. http://www.quirksmode.org/js/events/keys.html for keycodes
+function keyDown(event)
+{
+ var key;
+
+ if (!event)
+ var event = window.event;
+
+ // kludge around NS/IE differences
+ if (window.event)
+ key = window.event.keyCode;
+ else if (event.which)
+ key = event.which;
+ else
+ return true; // Yikes! unknown browser
+
+ // ignore event if key value is zero
+ // as for alt on Opera and Konqueror
+ if (!key)
+ return true;
+
+ // check for concurrent control/command/alt key
+ // but are these only present on mouse events?
+
+ if (event.ctrlKey || event.altKey || event.metaKey)
+ return true;
+
+ // dismiss table of contents if visible
+ if (isShownToc() && key != 9 && key != 16 && key != 38 && key != 40)
+ {
+ hideTableOfContents();
+
+ if (key == 27 || key == 84 || key == 67)
+ return cancel(event);
+ }
+
+ if (key == 34) // Page Down
+ {
+ nextSlide(false);
+ return cancel(event);
+ }
+ else if (key == 33) // Page Up
+ {
+ previousSlide(false);
+ return cancel(event);
+ }
+ else if (key == 32) // space bar
+ {
+ nextSlide(true);
+ return cancel(event);
+ }
+ else if (key == 37 || key == 38) // Left arrow || Up arrow
+ {
+ previousSlide(!event.shiftKey);
+ return cancel(event);
+ }
+ else if (key == 36) // Home
+ {
+ firstSlide();
+ return cancel(event);
+ }
+ else if (key == 35) // End
+ {
+ lastSlide();
+ return cancel(event);
+ }
+ else if (key == 39 || key == 40) // Right arrow || Down arrow
+ {
+ nextSlide(!event.shiftKey);
+ return cancel(event);
+ }
+ else if (key == 13) // Enter
+ {
+ if (outline)
+ {
+ if (outline.visible)
+ fold(outline);
+ else
+ unfold(outline);
+
+ return cancel(event);
+ }
+ }
+ else if (key == 188) // < for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 190) // > for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 189 || key == 109) // - for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 187 || key == 191 || key == 107) // = + for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 83) // S for smaller fonts
+ {
+ smaller();
+ return cancel(event);
+ }
+ else if (key == 66) // B for larger fonts
+ {
+ bigger();
+ return cancel(event);
+ }
+ else if (key == 90) // Z for last slide
+ {
+ lastSlide();
+ return cancel(event);
+ }
+ else if (key == 70) // F for toggle toolbar
+ {
+ toggleToolbar();
+ return cancel(event);
+ }
+ else if (key == 65) // A for toggle view single/all slides
+ {
+ toggleView();
+ return cancel(event);
+ }
+ else if (key == 75) // toggle action of left click for next page
+ {
+ mouseClickEnabled = !mouseClickEnabled;
+ alert((mouseClickEnabled ? "enabled" : "disabled") + " mouse click advance");
+ return cancel(event);
+ }
+ else if (key == 84 || key == 67) // T or C for table of contents
+ {
+ if (toc)
+ showTableOfContents();
+
+ return cancel(event);
+ }
+ else if (key == 72) // H for help
+ {
+ window.location = helpPage;
+ return cancel(event);
+ }
+
+ //else if (key == 93) // Windows menu key
+ //alert("lastShown is " + lastShown);
+ //else alert("key code is "+ key);
+
+
+ return true;
+}
+
+// make note of length of selected text
+// as this evaluates to zero in click event
+function mouseButtonUp(e)
+{
+ selectedTextLen = getSelectedText().length;
+}
+
+// right mouse button click is reserved for context menus
+// it is more reliable to detect rightclick than leftclick
+function mouseButtonClick(e)
+{
+ var rightclick = false;
+ var leftclick = false;
+ var middleclick = false;
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ if (e.which) // all browsers except IE
+ {
+ leftclick = (e.which == 1);
+ middleclick = (e.which == 2);
+ rightclick = (e.which == 3);
+ }
+ else if (e.button)
+ {
+ // Konqueror gives 1 for left, 4 for middle
+ // IE6 gives 0 for left and not 1 as I expected
+
+ if (e.button == 4)
+ middleclick = true;
+
+ // all browsers agree on 2 for right button
+ rightclick = (e.button == 2);
+ }
+ else leftclick = true;
+
+ // dismiss table of contents
+ hideTableOfContents();
+
+ if (selectedTextLen > 0)
+ {
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ return false;
+ }
+
+ // check if target is something that probably want's clicks
+ // e.g. embed, object, input, textarea, select, option
+
+ if (mouseClickEnabled && leftclick &&
+ target.nodeName != "EMBED" &&
+ target.nodeName != "OBJECT" &&
+ target.nodeName != "INPUT" &&
+ target.nodeName != "TEXTAREA" &&
+ target.nodeName != "SELECT" &&
+ target.nodeName != "OPTION")
+ {
+ nextSlide(true);
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ }
+}
+
+function previousSlide(incremental)
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ if ((incremental || slidenum == 0) && lastShown != null)
+ {
+ lastShown = hidePreviousItem(lastShown);
+ setEosStatus(false);
+ }
+ else if (slidenum > 0)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = slidenum - 1;
+ slide = slides[slidenum];
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ setEosStatus(true);
+ showSlide(slide);
+ }
+
+ setLocation();
+
+ if (!ns_pos)
+ refreshToolbar(200);
+ }
+}
+
+function nextSlide(incremental)
+{
+ if (!viewAll)
+ {
+ var slide, last = lastShown;
+
+ if (incremental || slidenum == slides.length - 1)
+ lastShown = revealNextItem(lastShown);
+
+ if ((!incremental || lastShown == null) && slidenum < slides.length - 1)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = slidenum + 1;
+ slide = slides[slidenum];
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ showSlide(slide);
+ }
+ else if (!lastShown)
+ {
+ if (last && incremental)
+ lastShown = last;
+ }
+
+ setLocation();
+
+ setEosStatus(!nextIncrementalItem(lastShown));
+
+ if (!ns_pos)
+ refreshToolbar(200);
+ }
+}
+
+// to first slide with nothing revealed
+// i.e. state at start of presentation
+function firstSlide()
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ if (slidenum != 0)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+
+ slidenum = 0;
+ slide = slides[slidenum];
+ lastShown = null;
+ setVisibilityAllIncremental("hidden");
+ showSlide(slide);
+ }
+
+ setEosStatus(!nextIncrementalItem(lastShown));
+ setLocation();
+ }
+}
+
+
+// to last slide with everything revealed
+// i.e. state at end of presentation
+function lastSlide()
+{
+ if (!viewAll)
+ {
+ var slide;
+
+ lastShown = null; //revealNextItem(lastShown);
+
+ if (lastShown == null && slidenum < slides.length - 1)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = slides.length - 1;
+ slide = slides[slidenum];
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+
+ showSlide(slide);
+ }
+ else
+ {
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+ }
+
+ setEosStatus(true);
+ setLocation();
+ }
+}
+
+function setEosStatus(state)
+{
+ if (eos)
+ eos.style.color = (state ? "rgb(240,240,240)" : "red");
+}
+
+function showSlide(slide)
+{
+ syncBackground(slide);
+ window.scrollTo(0,0);
+ slide.style.visibility = "visible";
+ slide.style.display = "block";
+}
+
+function hideSlide(slide)
+{
+ slide.style.visibility = "hidden";
+ slide.style.display = "none";
+}
+
+function beforePrint()
+{
+ showAllSlides();
+ hideToolbar();
+}
+
+function afterPrint()
+{
+ if (!viewAll)
+ {
+ singleSlideView();
+ showToolbar();
+ }
+}
+
+function printSlides()
+{
+ beforePrint();
+ window.print();
+ afterPrint();
+}
+
+function toggleView()
+{
+ if (viewAll)
+ {
+ singleSlideView();
+ showToolbar();
+ viewAll = 0;
+ }
+ else
+ {
+ showAllSlides();
+ hideToolbar();
+ viewAll = 1;
+ }
+}
+
+// prepare for printing
+function showAllSlides()
+{
+ var slide;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ slide = slides[i];
+
+ slide.style.position = "relative";
+ slide.style.borderTopStyle = "solid";
+ slide.style.borderTopWidth = "thin";
+ slide.style.borderTopColor = "black";
+
+ try {
+ if (i == 0)
+ slide.style.pageBreakBefore = "avoid";
+ else
+ slide.style.pageBreakBefore = "always";
+ }
+ catch (e)
+ {
+ //do nothing
+ }
+
+ setVisibilityAllIncremental("visible");
+ showSlide(slide);
+ }
+
+ var note;
+
+ for (var i = 0; i < notes.length; ++i)
+ {
+ showSlide(notes[i]);
+ }
+
+ // no easy way to render background under each slide
+ // without duplicating the background divs for each slide
+ // therefore hide backgrounds to avoid messing up slides
+ hideBackgrounds();
+}
+
+// restore after printing
+function singleSlideView()
+{
+ var slide;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ slide = slides[i];
+
+ slide.style.position = "absolute";
+
+ if (i == slidenum)
+ {
+ slide.style.borderStyle = "none";
+ showSlide(slide);
+ }
+ else
+ {
+ slide.style.borderStyle = "none";
+ hideSlide(slide);
+ }
+ }
+
+ setVisibilityAllIncremental("visible");
+ lastShown = previousIncrementalItem(null);
+
+ var note;
+
+ for (var i = 0; i < notes.length; ++i)
+ {
+ hideSlide(notes[i]);
+ }
+}
+
+// the string str is a whitespace separated list of tokens
+// test if str contains a particular token, e.g. "slide"
+function hasToken(str, token)
+{
+ if (str)
+ {
+ // define pattern as regular expression
+ var pattern = /\w+/g;
+
+ // check for matches
+ // place result in array
+ var result = str.match(pattern);
+
+ // now check if desired token is present
+ for (var i = 0; i < result.length; i++)
+ {
+ if (result[i] == token)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function getClassList(element)
+{
+ if (typeof window.pageYOffset =='undefined')
+ return element.getAttribute("className");
+
+ return element.getAttribute("class");
+}
+
+function hasClass(element, name)
+{
+ var regexp = new RegExp("(^| )" + name + "\W*");
+
+ if (regexp.test(getClassList(element)))
+ return true;
+
+ return false;
+
+}
+
+function removeClass(element, name)
+{
+ // IE getAttribute requires "class" to be "className"
+ var clsname = ns_pos ? "class" : "className";
+ var clsval = element.getAttribute(clsname);
+
+ var regexp = new RegExp("(^| )" + name + "\W*");
+
+ if (clsval)
+ {
+ clsval = clsval.replace(regexp, "");
+ element.setAttribute(clsname, clsval);
+ }
+}
+
+function addClass(element, name)
+{
+ if (!hasClass(element, name))
+ {
+ // IE getAttribute requires "class" to be "className"
+ var clsname = ns_pos ? "class" : "className";
+ var clsval = element.getAttribute(clsname);
+ element.setAttribute(clsname, (clsval ? clsval + " " + name : name));
+ }
+}
+
+// wysiwyg editors make it hard to use div elements
+// e.g. amaya loses the div when you copy and paste
+// this function wraps div elements around implicit
+// slides which start with an h1 element and continue
+// up to the next heading or div element
+function wrapImplicitSlides()
+{
+ var i, heading, node, next, div;
+ var headings = document.getElementsByTagName("h1");
+
+ if (!headings)
+ return;
+
+ for (i = 0; i < headings.length; ++i)
+ {
+ heading = headings[i];
+
+ if (heading.parentNode != document.body)
+ continue;
+
+ node = heading.nextSibling;
+
+ div = document.createElement("div");
+ div.setAttribute((ns_pos ? "class" : "className"), "slide");
+ document.body.replaceChild(div, heading);
+ div.appendChild(heading);
+
+ while (node)
+ {
+ if (node.nodeType == 1 && // an element
+ (node.nodeName == "H1" ||
+ node.nodeName == "h1" ||
+ node.nodeName == "DIV" ||
+ node.nodeName == "div"))
+ break;
+
+ next = node.nextSibling;
+ node = document.body.removeChild(node);
+ div.appendChild(node);
+ node = next;
+ }
+ }
+}
+
+// return new array of all slides
+function collectSlides()
+{
+ var slides = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "slide"))
+ {
+ // add slide to collection
+ slides[slides.length] = div;
+
+ // hide each slide as it is found
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+
+ // add dummy <br/> at end for scrolling hack
+ var node1 = document.createElement("br");
+ div.appendChild(node1);
+ var node2 = document.createElement("br");
+ div.appendChild(node2);
+ }
+ else if (hasClass(div, "background"))
+ { // work around for Firefox SVG reload bug
+ // which otherwise replaces 1st SVG graphic with 2nd
+ div.style.display = "block";
+ }
+ }
+
+ return slides;
+}
+
+// return new array of all <div class="handout">
+function collectNotes()
+{
+ var notes = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "handout"))
+ {
+ // add slide to collection
+ notes[notes.length] = div;
+
+ // hide handout notes as they are found
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+ }
+ }
+
+ return notes;
+}
+
+// return new array of all <div class="background">
+// including named backgrounds e.g. class="background titlepage"
+function collectBackgrounds()
+{
+ var backgrounds = new Array();
+ var divs = document.body.getElementsByTagName("div");
+
+ for (var i = 0; i < divs.length; ++i)
+ {
+ div = divs.item(i);
+
+ if (hasClass(div, "background"))
+ {
+ // add slide to collection
+ backgrounds[backgrounds.length] = div;
+
+ // hide named backgrounds as they are found
+ // e.g. class="background epilog"
+ if (getClassList(div) != "background")
+ {
+ div.style.display = "none";
+ div.style.visibility = "hidden";
+ }
+ }
+ }
+
+ return backgrounds;
+}
+
+// show just the backgrounds pertinent to this slide
+function syncBackground(slide)
+{
+ var background;
+ var bgColor;
+
+ if (slide.currentStyle)
+ bgColor = slide.currentStyle["backgroundColor"];
+ else if (document.defaultView)
+ {
+ var styles = document.defaultView.getComputedStyle(slide,null);
+
+ if (styles)
+ bgColor = styles.getPropertyValue("background-color");
+ else // broken implementation probably due Safari or Konqueror
+ {
+ //alert("defective implementation of getComputedStyle()");
+ bgColor = "transparent";
+ }
+ }
+ else
+ bgColor == "transparent";
+
+ if (bgColor == "transparent")
+ {
+ var slideClass = getClassList(slide);
+
+ for (var i = 0; i < backgrounds.length; i++)
+ {
+ background = backgrounds[i];
+
+ var bgClass = getClassList(background);
+
+ if (matchingBackground(slideClass, bgClass))
+ {
+ background.style.display = "block";
+ background.style.visibility = "visible";
+ }
+ else
+ {
+ background.style.display = "none";
+ background.style.visibility = "hidden";
+ }
+ }
+ }
+ else // forcibly hide all backgrounds
+ hideBackgrounds();
+}
+
+function hideBackgrounds()
+{
+ for (var i = 0; i < backgrounds.length; i++)
+ {
+ background = backgrounds[i];
+ background.style.display = "none";
+ background.style.visibility = "hidden";
+ }
+}
+
+// compare classes for slide and background
+function matchingBackground(slideClass, bgClass)
+{
+ if (bgClass == "background")
+ return true;
+
+ // define pattern as regular expression
+ var pattern = /\w+/g;
+
+ // check for matches and place result in array
+ var result = slideClass.match(pattern);
+
+ // now check if desired name is present for background
+ for (var i = 0; i < result.length; i++)
+ {
+ if (hasToken(bgClass, result[i]))
+ return true;
+ }
+
+ return false;
+}
+
+// left to right traversal of root's content
+function nextNode(root, node)
+{
+ if (node == null)
+ return root.firstChild;
+
+ if (node.firstChild)
+ return node.firstChild;
+
+ if (node.nextSibling)
+ return node.nextSibling;
+
+ for (;;)
+ {
+ node = node.parentNode;
+
+ if (!node || node == root)
+ break;
+
+ if (node && node.nextSibling)
+ return node.nextSibling;
+ }
+
+ return null;
+}
+
+// right to left traversal of root's content
+function previousNode(root, node)
+{
+ if (node == null)
+ {
+ node = root.lastChild;
+
+ if (node)
+ {
+ while (node.lastChild)
+ node = node.lastChild;
+ }
+
+ return node;
+ }
+
+ if (node.previousSibling)
+ {
+ node = node.previousSibling;
+
+ while (node.lastChild)
+ node = node.lastChild;
+
+ return node;
+ }
+
+ if (node.parentNode != root)
+ return node.parentNode;
+
+ return null;
+}
+
+// HTML elements that can be used with class="incremental"
+// note that you can also put the class on containers like
+// up, ol, dl, and div to make their contents appear
+// incrementally. Upper case is used since this is what
+// browsers report for HTML node names (text/html).
+function incrementalElementList()
+{
+ var inclist = new Array();
+ inclist["P"] = true;
+ inclist["PRE"] = true;
+ inclist["LI"] = true;
+ inclist["BLOCKQUOTE"] = true;
+ inclist["DT"] = true;
+ inclist["DD"] = true;
+ inclist["H2"] = true;
+ inclist["H3"] = true;
+ inclist["H4"] = true;
+ inclist["H5"] = true;
+ inclist["H6"] = true;
+ inclist["SPAN"] = true;
+ inclist["ADDRESS"] = true;
+ inclist["TABLE"] = true;
+ inclist["TR"] = true;
+ inclist["TH"] = true;
+ inclist["TD"] = true;
+ inclist["IMG"] = true;
+ inclist["OBJECT"] = true;
+ return inclist;
+}
+
+function nextIncrementalItem(node)
+{
+ var slide = slides[slidenum];
+
+ for (;;)
+ {
+ node = nextNode(slide, node);
+
+ if (node == null || node.parentNode == null)
+ break;
+
+ if (node.nodeType == 1) // ELEMENT
+ {
+ if (node.nodeName == "BR")
+ continue;
+
+ if (hasClass(node, "incremental")
+ && okayForIncremental[node.nodeName])
+ return node;
+
+ if (hasClass(node.parentNode, "incremental")
+ && !hasClass(node, "non-incremental"))
+ return node;
+ }
+ }
+
+ return node;
+}
+
+function previousIncrementalItem(node)
+{
+ var slide = slides[slidenum];
+
+ for (;;)
+ {
+ node = previousNode(slide, node);
+
+ if (node == null || node.parentNode == null)
+ break;
+
+ if (node.nodeType == 1)
+ {
+ if (node.nodeName == "BR")
+ continue;
+
+ if (hasClass(node, "incremental")
+ && okayForIncremental[node.nodeName])
+ return node;
+
+ if (hasClass(node.parentNode, "incremental")
+ && !hasClass(node, "non-incremental"))
+ return node;
+ }
+ }
+
+ return node;
+}
+
+// set visibility for all elements on current slide with
+// a parent element with attribute class="incremental"
+function setVisibilityAllIncremental(value)
+{
+ var node = nextIncrementalItem(null);
+
+ while (node)
+ {
+ node.style.visibility = value;
+ node = nextIncrementalItem(node);
+ }
+}
+
+// reveal the next hidden item on the slide
+// node is null or the node that was last revealed
+function revealNextItem(node)
+{
+ node = nextIncrementalItem(node);
+
+ if (node && node.nodeType == 1) // an element
+ node.style.visibility = "visible";
+
+ return node;
+}
+
+
+// exact inverse of revealNextItem(node)
+function hidePreviousItem(node)
+{
+ if (node && node.nodeType == 1) // an element
+ node.style.visibility = "hidden";
+
+ return previousIncrementalItem(node);
+}
+
+
+/* set click handlers on all anchors */
+function patchAnchors()
+{
+ var anchors = document.body.getElementsByTagName("a");
+
+ for (var i = 0; i < anchors.length; ++i)
+ {
+ anchors[i].onclick = clickedAnchor;
+ }
+}
+
+function clickedAnchor(e)
+{
+ if (!e)
+ var e = window.event;
+
+ // compare this.href with location.href
+ // for link to another slide in this doc
+
+ if (pageAddress(this.href) == pageAddress(location.href))
+ {
+ // yes, so find new slide number
+ var newslidenum = findSlideNumber(this.href);
+
+ if (newslidenum != slidenum)
+ {
+ slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = newslidenum;
+ slide = slides[slidenum];
+ showSlide(slide);
+ setLocation();
+ }
+ }
+ else if (this.target == null)
+ location.href = this.href;
+
+ this.blur();
+ stopPropagation(e);
+}
+
+function pageAddress(uri)
+{
+ var i = uri.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i < 0)
+ return uri; // yes
+
+ return uri.substr(0, i);
+}
+
+function showSlideNumber()
+{
+ slideNumElement.innerHTML = "slide".localize() + " " +
+ (slidenum + 1) + "/" + slides.length;
+}
+
+function setLocation()
+{
+ var uri = pageAddress(location.href);
+
+ //if (slidenum > 0)
+ uri = uri + "#(" + (slidenum+1) + ")";
+
+ if (uri != location.href && !khtml)
+ location.href = uri;
+
+ document.title = title + " (" + (slidenum+1) + ")";
+ //document.title = (slidenum+1) + ") " + slideName(slidenum);
+
+ showSlideNumber();
+}
+
+// find current slide based upon location
+// first find target anchor and then look
+// for associated div element enclosing it
+// finally map that to slide number
+function findSlideNumber(uri)
+{
+ // first get anchor from page location
+
+ var i = uri.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i < 0)
+ return 0; // yes
+
+ var anchor = unescape(uri.substr(i+1));
+
+ // now use anchor as XML ID to find target
+ var target = document.getElementById(anchor);
+
+ if (!target)
+ {
+ // does anchor look like "(2)" for slide 2 ??
+ // where first slide is (1)
+ var re = /\((\d)+\)/;
+
+ if (anchor.match(re))
+ {
+ var num = parseInt(anchor.substring(1, anchor.length-1));
+
+ if (num > slides.length)
+ num = 1;
+
+ if (--num < 0)
+ num = 0;
+
+ return num;
+ }
+
+ // accept [2] for backwards compatibility
+ re = /\[(\d)+\]/;
+
+ if (anchor.match(re))
+ {
+ var num = parseInt(anchor.substring(1, anchor.length-1));
+
+ if (num > slides.length)
+ num = 1;
+
+ if (--num < 0)
+ num = 0;
+
+ return num;
+ }
+
+ // oh dear unknown anchor
+ return 0;
+ }
+
+ // search for enclosing slide
+
+ while (true)
+ {
+ // browser coerces html elements to uppercase!
+ if (target.nodeName.toLowerCase() == "div" &&
+ hasClass(target, "slide"))
+ {
+ // found the slide element
+ break;
+ }
+
+ // otherwise try parent element if any
+
+ target = target.parentNode;
+
+ if (!target)
+ {
+ return 0; // no luck!
+ }
+ };
+
+ for (i = 0; i < slides.length; ++i)
+ {
+ if (slides[i] == target)
+ return i; // success
+ }
+
+ // oh dear still no luck
+ return 0;
+}
+
+// find slide name from first h1 element
+// default to document title + slide number
+function slideName(index)
+{
+ var name = null;
+ var slide = slides[index];
+
+ var heading = findHeading(slide);
+
+ if (heading)
+ name = extractText(heading);
+
+ if (!name)
+ name = title + "(" + (index + 1) + ")";
+
+ name.replace(/\&/g, "&");
+ name.replace(/\</g, "<");
+ name.replace(/\>/g, ">");
+
+ return name;
+}
+
+// find first h1 element in DOM tree
+function findHeading(node)
+{
+ if (!node || node.nodeType != 1)
+ return null;
+
+ if (node.nodeName == "H1" || node.nodeName == "h1")
+ return node;
+
+ var child = node.firstChild;
+
+ while (child)
+ {
+ node = findHeading(child);
+
+ if (node)
+ return node;
+
+ child = child.nextSibling;
+ }
+
+ return null;
+}
+
+// recursively extract text from DOM tree
+function extractText(node)
+{
+ if (!node)
+ return "";
+
+ // text nodes
+ if (node.nodeType == 3)
+ return node.nodeValue;
+
+ // elements
+ if (node.nodeType == 1)
+ {
+ node = node.firstChild;
+ var text = "";
+
+ while (node)
+ {
+ text = text + extractText(node);
+ node = node.nextSibling;
+ }
+
+ return text;
+ }
+
+ return "";
+}
+
+
+// find copyright text from meta element
+function findCopyright()
+{
+ var name, content;
+ var meta = document.getElementsByTagName("meta");
+
+ for (var i = 0; i < meta.length; ++i)
+ {
+ name = meta[i].getAttribute("name");
+ content = meta[i].getAttribute("content");
+
+ if (name == "copyright")
+ return content;
+ }
+
+ return null;
+}
+
+function findSizeAdjust()
+{
+ var name, content, offset;
+ var meta = document.getElementsByTagName("meta");
+
+ for (var i = 0; i < meta.length; ++i)
+ {
+ name = meta[i].getAttribute("name");
+ content = meta[i].getAttribute("content");
+
+ if (name == "font-size-adjustment")
+ return 1 * content;
+ }
+
+ return 0;
+}
+
+function addToolbar()
+{
+ var slideCounter, page;
+
+ var toolbar = createElement("div");
+ toolbar.setAttribute("class", "toolbar");
+
+ if (ns_pos) // a reasonably behaved browser
+ {
+ var right = document.createElement("div");
+ right.setAttribute("style", "float: right; text-align: right");
+
+ slideCounter = document.createElement("div")
+ slideCounter.innerHTML = "slide".localize() + " n/m";
+ right.appendChild(slideCounter);
+ toolbar.appendChild(right);
+
+ var left = document.createElement("div");
+ left.setAttribute("style", "text-align: left");
+
+ // global end of slide indicator
+ eos = document.createElement("span");
+ eos.innerHTML = "* ";
+ left.appendChild(eos);
+
+ var help = document.createElement("a");
+ help.setAttribute("href", helpPage);
+ help.setAttribute("title", helpText.localize());
+ help.innerHTML = "help?".localize();
+ left.appendChild(help);
+ helpAnchor = help; // save for focus hack
+
+ var gap1 = document.createTextNode(" ");
+ left.appendChild(gap1);
+
+ var contents = document.createElement("a");
+ contents.setAttribute("href", "javascript:toggleTableOfContents()");
+ contents.setAttribute("title", "table of contents".localize());
+ contents.innerHTML = "contents?".localize();
+ left.appendChild(contents);
+
+ var gap2 = document.createTextNode(" ");
+ left.appendChild(gap2);
+
+ var i = location.href.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i > 0)
+ page = location.href.substr(0, i);
+ else
+ page = location.href;
+
+ var start = document.createElement("a");
+ start.setAttribute("href", page);
+ start.setAttribute("title", "restart presentation".localize());
+ start.innerHTML = "restart?".localize();
+// start.setAttribute("href", "javascript:printSlides()");
+// start.setAttribute("title", "print all slides".localize());
+// start.innerHTML = "print!".localize();
+ left.appendChild(start);
+
+ var copyright = findCopyright();
+
+ if (copyright)
+ {
+ var span = document.createElement("span");
+ span.innerHTML = copyright;
+ span.style.color = "black";
+ span.style.marginLeft = "4em";
+ left.appendChild(span);
+ }
+
+ toolbar.appendChild(left);
+ }
+ else // IE so need to work around its poor CSS support
+ {
+ toolbar.style.position = (ie7 ? "fixed" : "absolute");
+ toolbar.style.zIndex = "200";
+ toolbar.style.width = "99.9%";
+ toolbar.style.height = "1.2em";
+ toolbar.style.top = "auto";
+ toolbar.style.bottom = "0";
+ toolbar.style.left = "0";
+ toolbar.style.right = "0";
+ toolbar.style.textAlign = "left";
+ toolbar.style.fontSize = "60%";
+ toolbar.style.color = "red";
+ toolbar.borderWidth = 0;
+ toolbar.style.background = "rgb(240,240,240)";
+
+ // would like to have help text left aligned
+ // and page counter right aligned, floating
+ // div's don't work, so instead use nested
+ // absolutely positioned div's.
+
+ var sp = document.createElement("span");
+ sp.innerHTML = " * ";
+ toolbar.appendChild(sp);
+ eos = sp; // end of slide indicator
+
+ var help = document.createElement("a");
+ help.setAttribute("href", helpPage);
+ help.setAttribute("title", helpText.localize());
+ help.innerHTML = "help?".localize();
+ toolbar.appendChild(help);
+ helpAnchor = help; // save for focus hack
+
+ var gap1 = document.createTextNode(" ");
+ toolbar.appendChild(gap1);
+
+ var contents = document.createElement("a");
+ contents.setAttribute("href", "javascript:toggleTableOfContents()");
+ contents.setAttribute("title", "table of contents".localize());
+ contents.innerHTML = "contents?".localize();
+ toolbar.appendChild(contents);
+
+ var gap2 = document.createTextNode(" ");
+ toolbar.appendChild(gap2);
+
+ var i = location.href.indexOf("#");
+
+ // check if anchor is entire page
+
+ if (i > 0)
+ page = location.href.substr(0, i);
+ else
+ page = location.href;
+
+ var start = document.createElement("a");
+ start.setAttribute("href", page);
+ start.setAttribute("title", "restart presentation".localize());
+ start.innerHTML = "restart?".localize();
+// start.setAttribute("href", "javascript:printSlides()");
+// start.setAttribute("title", "print all slides".localize());
+// start.innerHTML = "print!".localize();
+ toolbar.appendChild(start);
+
+ var copyright = findCopyright();
+
+ if (copyright)
+ {
+ var span = document.createElement("span");
+ span.innerHTML = copyright;
+ span.style.color = "black";
+ span.style.marginLeft = "2em";
+ toolbar.appendChild(span);
+ }
+
+ slideCounter = document.createElement("div")
+ slideCounter.style.position = "absolute";
+ slideCounter.style.width = "auto"; //"20%";
+ slideCounter.style.height = "1.2em";
+ slideCounter.style.top = "auto";
+ slideCounter.style.bottom = 0;
+ slideCounter.style.right = "0";
+ slideCounter.style.textAlign = "right";
+ slideCounter.style.color = "red";
+ slideCounter.style.background = "rgb(240,240,240)";
+
+ slideCounter.innerHTML = "slide".localize() + " n/m";
+ toolbar.appendChild(slideCounter);
+ }
+
+ // ensure that click isn't passed through to the page
+ toolbar.onclick = stopPropagation;
+ document.body.appendChild(toolbar);
+ slideNumElement = slideCounter;
+ setEosStatus(false);
+
+ return toolbar;
+}
+
+function isShownToc()
+{
+ if (toc && toc.style.visible == "visible")
+ return true;
+
+ return false;
+}
+
+function showTableOfContents()
+{
+ if (toc)
+ {
+ if (toc.style.visibility != "visible")
+ {
+ toc.style.visibility = "visible";
+ toc.style.display = "block";
+ toc.focus();
+
+ if (ie7 && slidenum == 0)
+ setTimeout("ieHack()", 100);
+ }
+ else
+ hideTableOfContents();
+ }
+}
+
+function hideTableOfContents()
+{
+ if (toc && toc.style.visibility != "hidden")
+ {
+ toc.style.visibility = "hidden";
+ toc.style.display = "none";
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+}
+
+function toggleTableOfContents()
+{
+ if (toc)
+ {
+ if (toc.style.visible != "visible")
+ showTableOfContents();
+ else
+ hideTableOfContents();
+ }
+}
+
+// called on clicking toc entry
+function gotoEntry(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ if (target && target.nodeType == 1)
+ {
+ var uri = target.getAttribute("href");
+
+ if (uri)
+ {
+ //alert("going to " + uri);
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = findSlideNumber(uri);
+ slide = slides[slidenum];
+ lastShown = null;
+ setLocation();
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ showSlide(slide);
+ //target.focus();
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+ }
+
+ hideTableOfContents(e);
+ if (ie7) ieHack();
+ stopPropagation(e);
+ return cancel(e);
+}
+
+// called onkeydown for toc entry
+function gotoTocEntry(event)
+{
+ var key;
+
+ if (!event)
+ var event = window.event;
+
+ // kludge around NS/IE differences
+ if (window.event)
+ key = window.event.keyCode;
+ else if (event.which)
+ key = event.which;
+ else
+ return true; // Yikes! unknown browser
+
+ // ignore event if key value is zero
+ // as for alt on Opera and Konqueror
+ if (!key)
+ return true;
+
+ // check for concurrent control/command/alt key
+ // but are these only present on mouse events?
+
+ if (event.ctrlKey || event.altKey)
+ return true;
+
+ if (key == 13)
+ {
+ var uri = this.getAttribute("href");
+
+ if (uri)
+ {
+ //alert("going to " + uri);
+ var slide = slides[slidenum];
+ hideSlide(slide);
+ slidenum = findSlideNumber(uri);
+ slide = slides[slidenum];
+ lastShown = null;
+ setLocation();
+ setVisibilityAllIncremental("hidden");
+ setEosStatus(!nextIncrementalItem(lastShown));
+ showSlide(slide);
+ //target.focus();
+
+ try
+ {
+ if (!opera)
+ helpAnchor.focus();
+ }
+ catch (e)
+ {
+ }
+ }
+
+ hideTableOfContents();
+ if (ie7) ieHack();
+ return cancel(event);
+ }
+
+ if (key == 40 && this.next)
+ {
+ this.next.focus();
+ return cancel(event);
+ }
+
+ if (key == 38 && this.previous)
+ {
+ this.previous.focus();
+ return cancel(event);
+ }
+
+ return true;
+}
+
+function isTitleSlide(slide)
+{
+ return hasClass(slide, "title");
+}
+
+// create div element with links to each slide
+function tableOfContents()
+{
+ var toc = document.createElement("div");
+ addClass(toc, "toc");
+ //toc.setAttribute("tabindex", "0");
+
+ var heading = document.createElement("div");
+ addClass(heading, "toc-heading");
+ heading.innerHTML = "Table of Contents".localize();
+
+ heading.style.textAlign = "center";
+ heading.style.width = "100%";
+ heading.style.margin = "0";
+ heading.style.marginBottom = "1em";
+ heading.style.borderBottomStyle = "solid";
+ heading.style.borderBottomColor = "rgb(180,180,180)";
+ heading.style.borderBottomWidth = "1px";
+
+ toc.appendChild(heading);
+ var previous = null;
+
+ for (var i = 0; i < slides.length; ++i)
+ {
+ var title = hasClass(slides[i], "title");
+ var num = document.createTextNode((i + 1) + ". ");
+
+ toc.appendChild(num);
+
+ var a = document.createElement("a");
+ a.setAttribute("href", "#(" + (i+1) + ")");
+
+ if (title)
+ addClass(a, "titleslide");
+
+ var name = document.createTextNode(slideName(i));
+ a.appendChild(name);
+ a.onclick = gotoEntry;
+ a.onkeydown = gotoTocEntry;
+ a.previous = previous;
+
+ if (previous)
+ previous.next = a;
+
+ toc.appendChild(a);
+
+ if (i == 0)
+ toc.first = a;
+
+ if (i < slides.length - 1)
+ {
+ var br = document.createElement("br");
+ toc.appendChild(br);
+ }
+
+ previous = a;
+ }
+
+ toc.focus = function () {
+ if (this.first)
+ this.first.focus();
+ }
+
+ toc.onclick = function (e) {
+ e||(e=window.event);
+ hideTableOfContents();
+ stopPropagation(e);
+
+ if (e.cancel != undefined)
+ e.cancel = true;
+
+ if (e.returnValue != undefined)
+ e.returnValue = false;
+
+ return false;
+ };
+
+ toc.style.position = "absolute";
+ toc.style.zIndex = "300";
+ toc.style.width = "60%";
+ toc.style.maxWidth = "30em";
+ toc.style.height = "30em";
+ toc.style.overflow = "auto";
+ toc.style.top = "auto";
+ toc.style.right = "auto";
+ toc.style.left = "4em";
+ toc.style.bottom = "4em";
+ toc.style.padding = "1em";
+ toc.style.background = "rgb(240,240,240)";
+ toc.style.borderStyle = "solid";
+ toc.style.borderWidth = "2px";
+ toc.style.fontSize = "60%";
+
+ document.body.insertBefore(toc, document.body.firstChild);
+ return toc;
+}
+
+function replaceByNonBreakingSpace(str)
+{
+ for (var i = 0; i < str.length; ++i)
+ str[i] = 160;
+}
+
+
+function initOutliner()
+{
+ var items = document.getElementsByTagName("LI");
+
+ for (var i = 0; i < items.length; ++i)
+ {
+ var target = items[i];
+
+ if (!hasClass(target.parentNode, "outline"))
+ continue;
+
+ target.onclick = outlineClick;
+
+ if (!ns_pos)
+ {
+ target.onmouseover = hoverOutline;
+ target.onmouseout = unhoverOutline;
+ }
+
+ if (foldable(target))
+ {
+ target.foldable = true;
+ target.onfocus = function () {outline = this;};
+ target.onblur = function () {outline = null;};
+
+ if (!target.getAttribute("tabindex"))
+ target.setAttribute("tabindex", "0");
+
+ if (hasClass(target, "expand"))
+ unfold(target);
+ else
+ fold(target);
+ }
+ else
+ {
+ addClass(target, "nofold");
+ target.visible = true;
+ target.foldable = false;
+ }
+ }
+}
+
+function foldable(item)
+{
+ if (!item || item.nodeType != 1)
+ return false;
+
+ var node = item.firstChild;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node))
+ return true;
+
+ node = node.nextSibling;
+ }
+
+ return false;
+}
+
+function fold(item)
+{
+ if (item)
+ {
+ removeClass(item, "unfolded");
+ addClass(item, "folded");
+ }
+
+ var node = item ? item.firstChild : null;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node)) // element
+ {
+ // note that getElementStyle won't work for Safari 1.3
+ node.display = getElementStyle(node, "display", "display");
+ node.style.display = "none";
+ node.style.visibility = "hidden";
+ }
+
+ node = node.nextSibling;
+ }
+
+ item.visible = false;
+}
+
+function unfold(item)
+{
+ if (item)
+ {
+ addClass(item, "unfolded");
+ removeClass(item, "folded");
+ }
+
+ var node = item ? item.firstChild : null;
+
+ while (node)
+ {
+ if (node.nodeType == 1 && isBlock(node)) // element
+ {
+ // with fallback for Safari, see above
+ node.style.display = (node.display ? node.display : "block");
+ node.style.visibility = "visible";
+ }
+
+ node = node.nextSibling;
+ }
+
+ item.visible = true;
+}
+
+function outlineClick(e)
+{
+ var rightclick = false;
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (!target)
+ return true;
+
+ if (e.which)
+ rightclick = (e.which == 3);
+ else if (e.button)
+ rightclick = (e.button == 2);
+
+ if (!rightclick && target.visible != undefined)
+ {
+ if (target.foldable)
+ {
+ if (target.visible)
+ fold(target);
+ else
+ unfold(target);
+ }
+
+ stopPropagation(e);
+ e.cancel = true;
+ e.returnValue = false;
+ }
+
+ return false;
+}
+
+function hoverOutline(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (target && target.foldable)
+ target.style.cursor = "pointer";
+
+ return true;
+}
+
+function unhoverOutline(e)
+{
+ var target;
+
+ if (!e)
+ var e = window.event;
+
+ if (e.target)
+ target = e.target;
+ else if (e.srcElement)
+ target = e.srcElement;
+
+ // work around Safari bug
+ if (target.nodeType == 3)
+ target = target.parentNode;
+
+ while (target && target.visible == undefined)
+ target = target.parentNode;
+
+ if (target)
+ target.style.cursor = "default";
+
+ return true;
+}
+
+
+function stopPropagation(e)
+{
+ if (window.event)
+ {
+ window.event.cancelBubble = true;
+ //window.event.returnValue = false;
+ }
+ else if (e)
+ {
+ e.cancelBubble = true;
+ e.stopPropagation();
+ //e.preventDefault();
+ }
+}
+
+/* can't rely on display since we set that to none to hide things */
+function isBlock(elem)
+{
+ var tag = elem.nodeName;
+
+ return tag == "OL" || tag == "UL" || tag == "P" ||
+ tag == "LI" || tag == "TABLE" || tag == "PRE" ||
+ tag == "H1" || tag == "H2" || tag == "H3" ||
+ tag == "H4" || tag == "H5" || tag == "H6" ||
+ tag == "BLOCKQUOTE" || tag == "ADDRESS";
+}
+
+function getElementStyle(elem, IEStyleProp, CSSStyleProp)
+{
+ if (elem.currentStyle)
+ {
+ return elem.currentStyle[IEStyleProp];
+ }
+ else if (window.getComputedStyle)
+ {
+ var compStyle = window.getComputedStyle(elem, "");
+ return compStyle.getPropertyValue(CSSStyleProp);
+ }
+ return "";
+}
+
+// works with text/html and text/xhtml+xml with thanks to Simon Willison
+function createElement(element)
+{
+ if (typeof document.createElementNS != 'undefined')
+ {
+ return document.createElementNS('http://www.w3.org/1999/xhtml', element);
+ }
+
+ if (typeof document.createElement != 'undefined')
+ {
+ return document.createElement(element);
+ }
+
+ return false;
+}
+
+// designed to work with both text/html and text/xhtml+xml
+function getElementsByTagName(name)
+{
+ if (typeof document.getElementsByTagNameNS != 'undefined')
+ {
+ return document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', name);
+ }
+
+ if (typeof document.getElementsByTagName != 'undefined')
+ {
+ return document.getElementsByTagName(name);
+ }
+
+ return null;
+}
+
+/*
+// clean alternative to innerHTML method, but on IE6
+// it doesn't work with named entities like
+// which need to be replaced by numeric entities
+function insertText(element, text)
+{
+ try
+ {
+ element.textContent = text; // DOM3 only
+ }
+ catch (e)
+ {
+ if (element.firstChild)
+ {
+ // remove current children
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+ }
+
+ element.appendChild(document.createTextNode(text));
+ }
+}
+
+// as above, but as method of all element nodes
+// doesn't work in IE6 which doesn't allow you to
+// add methods to the HTMLElement prototype
+if (HTMLElement != undefined)
+{
+ HTMLElement.prototype.insertText = function(text) {
+ var element = this;
+
+ try
+ {
+ element.textContent = text; // DOM3 only
+ }
+ catch (e)
+ {
+ if (element.firstChild)
+ {
+ // remove current children
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+ }
+
+ element.appendChild(document.createTextNode(text));
+ }
+ };
+}
+*/
+
+function getSelectedText()
+{
+ try
+ {
+ if (window.getSelection)
+ return window.getSelection().toString();
+
+ if (document.getSelection)
+ return document.getSelection().toString();
+
+ if (document.selection)
+ return document.selection.createRange().text;
+ }
+ catch (e)
+ {
+ return "";
+ }
+ return "";
+}