diapositives/Slidy/slidy.js
changeset 252 d3a405d0742f
equal deleted inserted replaced
251:4aa28098b2c2 252:d3a405d0742f
       
     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, "&amp;");
       
  1882    name.replace(/\</g, "&lt;");
       
  1883    name.replace(/\>/g, "&gt;");
       
  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 = "&nbsp;&nbsp;*&nbsp;";
       
  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 &nbsp;
       
  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 }