PageRenderTime 206ms CodeModel.GetById 104ms app.highlight 88ms RepoModel.GetById 1ms app.codeStats 1ms

/samples/scalate-presentation/src/scripts/slidy.js

http://github.com/scalate/scalate
JavaScript | 2881 lines | 2105 code | 535 blank | 241 comment | 634 complexity | 4b09909ae79f7bc1201001ec7e146571 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/* slidy.js
   2
   3   Copyright (c) 2005-2010 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   Defines single name "w3c_slidy" in global namespace
  11   Adds event handlers without trampling on any others
  12*/
  13
  14// the slidy object implementation
  15var w3c_slidy = {
  16  // classify which kind of browser we're running under
  17  ns_pos: (typeof window.pageYOffset!='undefined'),
  18  khtml: ((navigator.userAgent).indexOf("KHTML") >= 0 ? true : false),
  19  opera: ((navigator.userAgent).indexOf("Opera") >= 0 ? true : false),
  20  ipad: ((navigator.userAgent).indexOf("iPad") >= 0 ? true : false),
  21  iphone: ((navigator.userAgent).indexOf("iPhone") >= 0 ? true : false),
  22  ie: (typeof document.all != "undefined" && !this.opera),
  23  ie6: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 6") != -1),
  24  ie7: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 7") != -1),
  25  ie8: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 8") != -1),
  26  ie9: (!this.ns_pos && navigator.userAgent.indexOf("MSIE 9") != -1),
  27  keyboardless: (this.ipad || this.iphone),
  28
  29  // are we running as XHTML? (doesn't work on Opera)
  30  is_xhtml: /xml/.test(document.contentType),
  31
  32  slide_number: 0, // integer slide count: 0, 1, 2, ...
  33  slide_number_element: null, // element containing slide number
  34  slides: [], // set to array of slide div's
  35  notes: [], // set to array of handout div's
  36  backgrounds: [], // set to array of background div's
  37  toolbar: null, // element containing toolbar
  38  title: null, // document title
  39  last_shown: null, // last incrementally shown item
  40  eos: null,  // span element for end of slide indicator
  41  toc: null, // table of contents
  42  outline: null, // outline element with the focus
  43  selected_text_len: 0, // length of drag selection on document
  44  view_all: 0,  // 1 to view all slides + handouts
  45  want_toolbar: true,  // user preference to show/hide toolbar
  46  mouse_click_enabled: true, // enables left click for next slide
  47  scroll_hack: 0, // IE work around for position: fixed
  48  disable_slide_click: false,  // used by clicked anchors
  49
  50  lang: "en", // updated to language specified by html file
  51
  52  help_anchor: null, // used for keyboard focus hack in showToolbar()
  53  help_page: "http://www.w3.org/Talks/Tools/Slidy2/help/help.html",
  54  help_text: "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  size_index: 0,
  58  size_adjustment: 0,
  59  sizes:  new Array("10pt", "12pt", "14pt", "16pt", "18pt", "20pt",
  60                    "22pt", "24pt", "26pt", "28pt", "30pt", "32pt"),
  61
  62  // needed for efficient resizing
  63  last_width: 0,
  64  last_height: 0,
  65
  66
  67  // Needed for cross browser support for relative width/height on
  68  // object elements. The work around is to save width/height attributes
  69  // and then to recompute absolute width/height dimensions on resizing
  70   objects: [],
  71
  72  // attach initialiation event handlers
  73  set_up: function () {
  74    var init = function() { w3c_slidy.init(); };
  75    if (typeof window.addEventListener != "undefined")
  76      window.addEventListener("load", init, false);
  77    else
  78      window.attachEvent("onload", init);
  79  },
  80
  81  hide_slides: function () {
  82    if (document.body && !w3c_slidy.initialized)
  83      document.body.style.visibility = "hidden";
  84    else
  85      setTimeout(w3c_slidy.hide_slides, 50);
  86  },
  87
  88  // hack to persuade IE to compute correct document height
  89  // as needed for simulating fixed positioning of toolbar
  90  ie_hack: function () {
  91    window.resizeBy(0,-1);
  92    window.resizeBy(0, 1);
  93  },
  94
  95  init: function () {
  96    //alert("slidy starting test 10");
  97    document.body.style.visibility = "visible";
  98    this.init_localization();
  99    this.add_toolbar();
 100    this.wrap_implicit_slides();
 101    this.collect_slides();
 102    this.collect_notes();
 103    this.collect_backgrounds();
 104    this.objects = document.body.getElementsByTagName("object");
 105    this.patch_anchors();
 106    this.slide_number = this.find_slide_number(location.href);
 107    window.offscreenbuffering = true;
 108    this.size_adjustment = this.find_size_adjust();
 109    this.time_left = this.find_duration();
 110    this.hide_image_toolbar();  // suppress IE image toolbar popup
 111    this.init_outliner();  // activate fold/unfold support
 112    this.title = document.title;
 113
 114    // work around for opera bug
 115    this.is_xhtml = (document.body.tagName == "BODY" ? false : true);
 116
 117    if (this.slides.length > 0)
 118    {
 119      var slide = this.slides[this.slide_number];
 120   
 121      if (this.slide_number > 0)
 122      {
 123        this.set_visibility_all_incremental("visible");
 124        this.last_shown = this.previous_incremental_item(null);
 125        this.set_eos_status(true);
 126      }
 127      else
 128      {
 129        this.last_shown = null;
 130        this.set_visibility_all_incremental("hidden");
 131        this.set_eos_status(!this.next_incremental_item(this.last_shown));
 132      }
 133
 134      this.set_location();
 135      this.add_class(this.slides[0], "first-slide");
 136      w3c_slidy.show_slide(slide);
 137    }
 138
 139    this.toc = this.table_of_contents();
 140
 141    this.add_initial_prompt();
 142
 143    // bind event handlers without interfering with custom page scripts
 144    // Tap events behave too weirdly to support clicks reliably on
 145    // iPhone and iPad, so exclude these from click handler
 146
 147    if (!this.keyboardless)
 148      this.add_listener(document.body, "click", this.mouse_button_click);
 149
 150    this.add_listener(document, "keydown", this.key_down);
 151    this.add_listener(document, "keypress", this.key_press);
 152    this.add_listener(window, "resize", this.resized);
 153    this.add_listener(window, "scroll", this.scrolled);
 154    this.add_listener(window, "unload", this.unloaded);
 155
 156    // this seems to be a debugging hack
 157    //if (!document.body.onclick)
 158    //  document.body.onclick = function () { };
 159
 160    this.single_slide_view();
 161
 162    //this.set_location();
 163
 164    this.resized();
 165
 166    if (this.ie7)
 167      setTimeout(w3c_slidy.ie_hack, 100);
 168
 169    this.show_toolbar();
 170
 171    // for back button detection
 172    setInterval(function () { w3c_slidy.check_location(); }, 200);
 173    w3c_slidy.initialized = true;
 174  },
 175
 176  // create div element with links to each slide
 177  table_of_contents: function () {
 178    var toc = this.create_element("div");
 179    this.add_class(toc, "slidy_toc hidden");
 180    //toc.setAttribute("tabindex", "0");
 181
 182    var heading = this.create_element("div");
 183    this.add_class(heading, "toc-heading");
 184    heading.innerHTML = this.localize("Table of Contents");
 185
 186    toc.appendChild(heading);
 187    var previous = null;
 188
 189    for (var i = 0; i < this.slides.length; ++i)
 190    {
 191      var title = this.has_class(this.slides[i], "title");
 192      var num = document.createTextNode((i + 1) + ". ");
 193
 194      toc.appendChild(num);
 195
 196      var a = this.create_element("a");
 197      a.setAttribute("href", "#(" + (i+1) + ")");
 198
 199      if (title)
 200        this.add_class(a, "titleslide");
 201
 202      var name = document.createTextNode(this.slide_name(i));
 203      a.appendChild(name);
 204      a.onclick = w3c_slidy.toc_click;
 205      a.onkeydown = w3c_slidy.toc_key_down;
 206      a.previous = previous;
 207
 208      if (previous)
 209        previous.next = a;
 210
 211      toc.appendChild(a);
 212
 213      if (i == 0)
 214        toc.first = a;
 215
 216      if (i < this.slides.length - 1)
 217      {
 218        var br = this.create_element("br");
 219        toc.appendChild(br);
 220      }
 221
 222      previous = a;
 223    }
 224
 225    toc.focus = function () {
 226      if (this.first)
 227        this.first.focus();
 228    }
 229
 230    toc.onmouseup = w3c_slidy.mouse_button_up;
 231
 232    toc.onclick = function (e) {
 233      e||(e=window.event);
 234
 235      if (w3c_slidy.selected_text_len <= 0)
 236         w3c_slidy.hide_table_of_contents(true);
 237
 238      w3c_slidy.stop_propagation(e);
 239    
 240      if (e.cancel != undefined)
 241        e.cancel = true;
 242      
 243      if (e.returnValue != undefined)
 244        e.returnValue = false;
 245      
 246      return false;
 247    };
 248
 249    document.body.insertBefore(toc, document.body.firstChild);
 250    return toc;
 251  },
 252
 253  is_shown_toc: function () {
 254    return !w3c_slidy.has_class(w3c_slidy.toc, "hidden");
 255  },
 256
 257  show_table_of_contents: function () {
 258    w3c_slidy.remove_class(w3c_slidy.toc, "hidden");
 259    var toc = w3c_slidy.toc;
 260    toc.focus();
 261
 262    if (w3c_slidy.ie7 && w3c_slidy.slide_number == 0)
 263      setTimeout(w3c_slidy.ie_hack, 100);
 264  },
 265
 266  hide_table_of_contents: function (focus) {
 267    w3c_slidy.add_class(w3c_slidy.toc, "hidden");
 268
 269    if (focus && !w3c_slidy.opera)
 270      w3c_slidy.help_anchor.focus();
 271  },
 272
 273  toggle_table_of_contents: function () {
 274    if (w3c_slidy.is_shown_toc())
 275      w3c_slidy.hide_table_of_contents(true);
 276    else
 277      w3c_slidy.show_table_of_contents();
 278  },
 279
 280  // called on clicking toc entry
 281  toc_click: function (e) {
 282    if (!e)
 283      e = window.event;
 284
 285    var target = w3c_slidy.get_target(e);
 286
 287    if (target && target.nodeType == 1)
 288    {
 289      var uri = target.getAttribute("href");
 290
 291      if (uri)
 292      {
 293        //alert("going to " + uri);
 294        var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 295        w3c_slidy.hide_slide(slide);
 296        w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
 297        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 298        w3c_slidy.last_shown = null;
 299        w3c_slidy.set_location();
 300        w3c_slidy.set_visibility_all_incremental("hidden");
 301        w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 302        w3c_slidy.show_slide(slide);
 303        //target.focus();
 304
 305        try
 306        {
 307          if (!w3c_slidy.opera)
 308            w3c_slidy.help_anchor.focus();
 309        }
 310        catch (e)
 311        {
 312        }
 313      }
 314    }
 315
 316    w3c_slidy.hide_table_of_contents(true);
 317    if (w3c_slidy.ie7) w3c_slidy.ie_hack();
 318    w3c_slidy.stop_propagation(e);
 319    return w3c_slidy.cancel(e);
 320  },
 321
 322  // called onkeydown for toc entry
 323  toc_key_down: function (event) {
 324    var key;
 325
 326    if (!event)
 327      var event = window.event;
 328
 329    // kludge around NS/IE differences 
 330    if (window.event)
 331      key = window.event.keyCode;
 332    else if (event.which)
 333      key = event.which;
 334    else
 335      return true; // Yikes! unknown browser
 336
 337    // ignore event if key value is zero
 338    // as for alt on Opera and Konqueror
 339    if (!key)
 340      return true;
 341
 342    // check for concurrent control/command/alt key
 343    // but are these only present on mouse events?
 344
 345    if (event.ctrlKey || event.altKey)
 346      return true;
 347
 348    if (key == 13)
 349    {
 350      var uri = this.getAttribute("href");
 351
 352      if (uri)
 353      {
 354        //alert("going to " + uri);
 355       var slide = w3c_slidy.slides[w3c_slidy.slide_number];
 356        w3c_slidy.hide_slide(slide);
 357        w3c_slidy.slide_number = w3c_slidy.find_slide_number(uri);
 358        slide = w3c_slidy.slides[w3c_slidy.slide_number];
 359        w3c_slidy.last_shown = null;
 360        w3c_slidy.set_location();
 361        w3c_slidy.set_visibility_all_incremental("hidden");
 362        w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
 363        w3c_slidy.show_slide(slide);
 364        //target.focus();
 365
 366        try
 367        {
 368          if (!w3c_slidy.opera)
 369            w3c_slidy.help_anchor.focus();
 370        }
 371        catch (e)
 372        {
 373        }
 374      }
 375
 376      w3c_slidy.hide_table_of_contents(true);
 377
 378      if (self.ie7)
 379       w3c_slidy.ie_hack();
 380
 381      return w3c_slidy.cancel(event);
 382    }
 383
 384    if (key == 40 && this.next)
 385    {
 386      this.next.focus();
 387      return w3c_slidy.cancel(event);
 388    }
 389
 390    if (key == 38 && this.previous)
 391    {
 392      this.previous.focus();
 393      return w3c_slidy.cancel(event);
 394    }
 395
 396    return true;
 397  },
 398
 399
 400  // ### OBSOLETE ###
 401  before_print: function () {
 402    this.show_all_slides();
 403    this.hide_toolbar();
 404    alert("before print");
 405  },
 406
 407  // ### OBSOLETE ###
 408  after_print: function () {
 409    if (!this.view_all)
 410    {
 411      this.single_slide_view();
 412      this.show_toolbar();
 413    }
 414    alert("after print");
 415  },
 416
 417  // ### OBSOLETE ###
 418  print_slides: function () {
 419    this.before_print();
 420    window.print();
 421    this.after_print();
 422  },
 423
 424  // ### OBSOLETE ?? ###
 425  toggle_view: function () {
 426    if (this.view_all)
 427    {
 428      this.single_slide_view();
 429      this.show_toolbar();
 430      this.view_all = 0;
 431    }
 432    else
 433    {
 434      this.show_all_slides();
 435      this.hide_toolbar();
 436      this.view_all = 1;
 437    }
 438  },
 439
 440  // prepare for printing  ### OBSOLETE ###
 441  show_all_slides: function () {
 442    this.remove_class(document.body, "single_slide");
 443    this.set_visibility_all_incremental("visible");
 444  },
 445
 446  // restore after printing  ### OBSOLETE ###
 447  single_slide_view: function () {
 448    this.add_class(document.body, "single_slide");
 449    this.set_visibility_all_incremental("visible");
 450    this.last_shown = this.previous_incremental_item(null);
 451  },
 452
 453  // suppress IE's image toolbar pop up
 454  hide_image_toolbar: function () {
 455    if (!this.ns_pos)
 456    {
 457      var images = document.getElementsByTagName("IMG");
 458
 459      for (var i = 0; i < images.length; ++i)
 460        images[i].setAttribute("galleryimg", "no");
 461    }
 462  },
 463
 464  unloaded: function (e) {
 465    //alert("unloaded");
 466  },
 467
 468  // Safari and Konqueror don't yet support getComputedStyle()
 469  // and they always reload page when location.href is updated
 470  is_KHTML: function () {
 471    var agent = navigator.userAgent;
 472    return (agent.indexOf("KHTML") >= 0 ? true : false);
 473  },
 474
 475  // find slide name from first h1 element
 476  // default to document title + slide number
 477  slide_name: function (index) {
 478    var name = null;
 479    var slide = this.slides[index];
 480
 481    var heading = this.find_heading(slide);
 482
 483    if (heading)
 484      name = this.extract_text(heading);
 485
 486    if (!name)
 487      name = this.title + "(" + (index + 1) + ")";
 488
 489    name.replace(/\&/g, "&amp;");
 490    name.replace(/\</g, "&lt;");
 491    name.replace(/\>/g, "&gt;");
 492
 493    return name;
 494  },
 495
 496  // find first h1 element in DOM tree
 497  find_heading: function (node) {
 498    if (!node || node.nodeType != 1)
 499      return null;
 500
 501    if (node.nodeName == "H1" || node.nodeName == "h1")
 502      return node;
 503
 504    var child = node.firstChild;
 505
 506    while (child)
 507    {
 508      node = this.find_heading(child);
 509
 510      if (node)
 511        return node;
 512
 513      child = child.nextSibling;
 514    }
 515
 516    return null;
 517  },
 518
 519  // recursively extract text from DOM tree
 520  extract_text: function (node) {
 521    if (!node)
 522      return "";
 523
 524    // text nodes
 525    if (node.nodeType == 3)
 526      return node.nodeValue;
 527
 528    // elements
 529    if (node.nodeType == 1)
 530    {
 531      node = node.firstChild;
 532      var text = "";
 533
 534      while (node)
 535      {
 536        text = text + this.extract_text(node);
 537        node = node.nextSibling;
 538      }
 539
 540      return text;
 541    }
 542
 543    return "";
 544  },
 545
 546  // find copyright text from meta element
 547  find_copyright: function () {
 548    var name, content;
 549    var meta = document.getElementsByTagName("meta");
 550
 551    for (var i = 0; i < meta.length; ++i)
 552    {
 553      name = meta[i].getAttribute("name");
 554      content = meta[i].getAttribute("content");
 555
 556      if (name == "copyright")
 557        return content;
 558    }
 559
 560    return null;
 561  },
 562
 563  find_size_adjust: function () {
 564    var name, content, offset;
 565    var meta = document.getElementsByTagName("meta");
 566
 567    for (var i = 0; i < meta.length; ++i)
 568    {
 569      name = meta[i].getAttribute("name");
 570      content = meta[i].getAttribute("content");
 571
 572      if (name == "font-size-adjustment")
 573        return 1 * content;
 574    }
 575
 576    return 1;
 577  },
 578
 579  // <meta name="duration" content="20" />  for 20 minutes
 580  find_duration: function () {
 581    var name, content, offset;
 582    var meta = document.getElementsByTagName("meta");
 583
 584    for (var i = 0; i < meta.length; ++i)
 585    {
 586      name = meta[i].getAttribute("name");
 587      content = meta[i].getAttribute("content");
 588
 589      if (name == "duration")
 590        return 60000 * content;
 591    }
 592
 593    return null;
 594  },
 595
 596  replace_by_non_breaking_space: function (str) {
 597    for (var i = 0; i < str.length; ++i)
 598      str[i] = 160;
 599  },
 600
 601  // ### CHECK ME ### is use of "li" okay for text/html?
 602  // for XHTML do we also need to specify namespace?
 603  init_outliner: function () {
 604    var items = document.getElementsByTagName("li");
 605
 606    for (var i = 0; i < items.length; ++i)
 607    {
 608      var target = items[i];
 609
 610      if (!this.has_class(target.parentNode, "outline"))
 611        continue;
 612
 613      target.onclick = this.outline_click;
 614/* ### more work needed for IE6
 615      if (!this.ns_pos)
 616      {
 617        target.onmouseover = this.hover_outline;
 618        target.onmouseout = this.unhover_outline;
 619      }
 620*/
 621      if (this.foldable(target))
 622      {
 623        target.foldable = true;
 624        target.onfocus = function () {w3c_slidy.outline = this;};
 625        target.onblur = function () {w3c_slidy.outline = null;};
 626
 627        if (!target.getAttribute("tabindex"))
 628          target.setAttribute("tabindex", "0");
 629
 630        if (this.has_class(target, "expand"))
 631          this.unfold(target);
 632        else
 633          this.fold(target);
 634      }
 635      else
 636      {
 637        this.add_class(target, "nofold");
 638        target.visible = true;
 639        target.foldable = false;
 640      }
 641    }
 642  },
 643
 644  foldable: function (item) {
 645    if (!item || item.nodeType != 1)
 646      return false;
 647
 648    var node = item.firstChild;
 649
 650    while (node)
 651    {
 652      if (node.nodeType == 1 && this.is_block(node))
 653        return true;
 654
 655      node = node.nextSibling;
 656    }
 657
 658    return false;
 659  },
 660
 661  // ### CHECK ME ### switch to add/remove "hidden" class
 662  fold: function (item) {
 663    if (item)
 664    {
 665      this.remove_class(item, "unfolded");
 666      this.add_class(item, "folded");
 667    }
 668
 669    var node = item ? item.firstChild : null;
 670
 671    while (node)
 672    {
 673      if (node.nodeType == 1 && this.is_block(node)) // element
 674      {
 675         w3c_slidy.add_class(node, "hidden");
 676      }
 677
 678      node = node.nextSibling;
 679    }
 680
 681    item.visible = false;
 682  },
 683
 684  // ### CHECK ME ### switch to add/remove "hidden" class
 685  unfold: function (item) {
 686    if (item)
 687    {
 688      this.add_class(item, "unfolded");
 689      this.remove_class(item, "folded");
 690    }
 691
 692    var node = item ? item.firstChild : null;
 693
 694    while (node)
 695    {
 696      if (node.nodeType == 1 && this.is_block(node)) // element
 697      {
 698        w3c_slidy.remove_class(node, "hidden");
 699      }
 700
 701      node = node.nextSibling;
 702    }
 703
 704    item.visible = true;
 705  },
 706
 707  outline_click: function (e) {
 708    if (!e)
 709      e = window.event;
 710
 711    var rightclick = false;
 712    var target = w3c_slidy.get_target(e);
 713
 714    while (target && target.visible == undefined)
 715      target = target.parentNode;
 716
 717    if (!target)
 718      return true;
 719
 720    if (e.which)
 721      rightclick = (e.which == 3);
 722    else if (e.button)
 723      rightclick = (e.button == 2);
 724
 725    if (!rightclick && target.visible != undefined)
 726    {
 727      if (target.foldable)
 728      {
 729        if (target.visible)
 730          w3c_slidy.fold(target);
 731        else
 732          w3c_slidy.unfold(target);
 733      }
 734
 735      w3c_slidy.stop_propagation(e);
 736      e.cancel = true;
 737      e.returnValue = false;
 738    }
 739
 740    return false;
 741  },
 742
 743  add_initial_prompt: function () {
 744    var prompt = this.create_element("div");
 745    prompt.setAttribute("class", "initial_prompt");
 746
 747    var p1 = this.create_element("p");
 748    prompt.appendChild(p1);
 749    p1.setAttribute("class", "help");
 750
 751    if (this.keyboardless)
 752      p1.innerHTML = "Tap footer to move to next slide";
 753    else
 754      p1.innerHTML = "Space or Right Arrow to move to next " +
 755                     "slide, click help below for more details";
 756
 757    this.add_listener(prompt, "click", function (e) {
 758      document.body.removeChild(prompt);
 759      w3c_slidy.stop_propagation(e);
 760    
 761      if (e.cancel != undefined)
 762        e.cancel = true;
 763      
 764      if (e.returnValue != undefined)
 765        e.returnValue = false;
 766      
 767      return false;
 768    });
 769
 770    document.body.appendChild(prompt);
 771    this.initial_prompt = prompt;
 772    setTimeout(function() {document.body.removeChild(prompt);}, 5000);
 773  },
 774
 775  add_toolbar: function () {
 776    var counter, page;
 777
 778     this.toolbar = this.create_element("div");
 779     this.toolbar.setAttribute("class", "toolbar");
 780
 781     // a reasonably behaved browser
 782     if (this.ns_pos || !this.ie6)
 783     {
 784       var right = this.create_element("div");
 785       right.setAttribute("style", "float: right; text-align: right");
 786
 787       counter = this.create_element("span")
 788       counter.innerHTML = this.localize("slide") + " n/m";
 789       right.appendChild(counter);
 790       this.toolbar.appendChild(right);
 791
 792       var left = this.create_element("div");
 793       left.setAttribute("style", "text-align: left");
 794
 795       // global end of slide indicator
 796       this.eos = this.create_element("span");
 797       this.eos.innerHTML = "* ";
 798       left.appendChild(this.eos);
 799
 800       var help = this.create_element("a");
 801       help.setAttribute("href", this.help_page);
 802       help.setAttribute("title", this.localize(this.help_text));
 803       help.innerHTML = this.localize("help?");
 804       left.appendChild(help);
 805       this.help_anchor = help;  // save for focus hack
 806
 807       var gap1 = document.createTextNode(" ");
 808       left.appendChild(gap1);
 809
 810       var contents = this.create_element("a");
 811       contents.setAttribute("href", "javascript:w3c_slidy.toggle_table_of_contents()");
 812       contents.setAttribute("title", this.localize("table of contents"));
 813       contents.innerHTML = this.localize("contents?");
 814       left.appendChild(contents);
 815
 816       var gap2 = document.createTextNode(" ");
 817       left.appendChild(gap2);
 818
 819       var copyright = this.find_copyright();
 820
 821       if (copyright)
 822       {
 823         var span = this.create_element("span");
 824         span.className = "copyright";
 825         span.innerHTML = copyright;
 826         left.appendChild(span);
 827       }
 828
 829       this.toolbar.setAttribute("tabindex", "0");
 830       this.toolbar.appendChild(left);
 831     }
 832     else // IE6 so need to work around its poor CSS support
 833     {
 834       this.toolbar.style.position = (this.ie7 ? "fixed" : "absolute");
 835       this.toolbar.style.zIndex = "200";
 836       this.toolbar.style.width = "99.9%";
 837       this.toolbar.style.height = "1.2em";
 838       this.toolbar.style.top = "auto";
 839       this.toolbar.style.bottom = "0";
 840       this.toolbar.style.left = "0";
 841       this.toolbar.style.right = "0";
 842       this.toolbar.style.textAlign = "left";
 843       this.toolbar.style.fontSize = "60%";
 844       this.toolbar.style.color = "red";
 845       this.toolbar.borderWidth = 0;
 846       this.toolbar.className = "toolbar";
 847       this.toolbar.style.background = "rgb(240,240,240)";
 848
 849       // would like to have help text left aligned
 850       // and page counter right aligned, floating
 851       // div's don't work, so instead use nested
 852       // absolutely positioned div's.
 853
 854       var sp = this.create_element("span");
 855       sp.innerHTML = "&nbsp;&nbsp;*&nbsp;";
 856       this.toolbar.appendChild(sp);
 857       this.eos = sp;  // end of slide indicator
 858
 859       var help = this.create_element("a");
 860       help.setAttribute("href", this.help_page);
 861       help.setAttribute("title", this.localize(this.help_text));
 862       help.innerHTML = this.localize("help?");
 863       this.toolbar.appendChild(help);
 864       this.help_anchor = help;  // save for focus hack
 865
 866       var gap1 = document.createTextNode(" ");
 867       this.toolbar.appendChild(gap1);
 868
 869       var contents = this.create_element("a");
 870       contents.setAttribute("href", "javascript:toggleTableOfContents()");
 871       contents.setAttribute("title", this.localize("table of contents".localize));
 872       contents.innerHTML = this.localize("contents?");
 873       this.toolbar.appendChild(contents);
 874
 875       var gap2 = document.createTextNode(" ");
 876       this.toolbar.appendChild(gap2);
 877
 878       var copyright = this.find_copyright();
 879
 880       if (copyright)
 881       {
 882         var span = this.create_element("span");
 883         span.innerHTML = copyright;
 884         span.style.color = "black";
 885         span.style.marginLeft = "0.5em";
 886         this.toolbar.appendChild(span);
 887       }
 888
 889       counter = this.create_element("div")
 890       counter.style.position = "absolute";
 891       counter.style.width = "auto"; //"20%";
 892       counter.style.height = "1.2em";
 893       counter.style.top = "auto";
 894       counter.style.bottom = 0;
 895       counter.style.right = "0";
 896       counter.style.textAlign = "right";
 897       counter.style.color = "red";
 898       counter.style.background = "rgb(240,240,240)";
 899
 900       counter.innerHTML = this.localize("slide") + " n/m";
 901       this.toolbar.appendChild(counter);
 902     }
 903
 904     // ensure that click isn't passed through to the page
 905     this.toolbar.onclick =
 906         function (e) {
 907           if (!e)
 908             e = window.event;
 909
 910           var target = e.target;
 911
 912           if (!target && e.srcElement)
 913             target = e.srcElement;
 914
 915           // work around Safari bug
 916           if (target && target.nodeType == 3)
 917             target = target.parentNode;
 918
 919           w3c_slidy.stop_propagation(e);
 920
 921           if (target && target.nodeName.toLowerCase() != "a")
 922             w3c_slidy.mouse_button_click(e);
 923         };
 924
 925     this.slide_number_element = counter;
 926     this.set_eos_status(false);
 927     document.body.appendChild(this.toolbar);
 928  },
 929
 930  // wysiwyg editors make it hard to use div elements
 931  // e.g. amaya loses the div when you copy and paste
 932  // this function wraps div elements around implicit
 933  // slides which start with an h1 element and continue
 934  // up to the next heading or div element
 935  wrap_implicit_slides: function () {
 936    var i, heading, node, next, div;
 937    var headings = document.getElementsByTagName("h1");
 938
 939    if (!headings)
 940      return;
 941
 942    for (i = 0; i < headings.length; ++i)
 943    {
 944      heading = headings[i];
 945
 946      if (heading.parentNode != document.body)
 947        continue;
 948
 949      node = heading.nextSibling;
 950
 951      div = document.createElement("div");
 952      this.add_class(div, "slide");
 953      document.body.replaceChild(div, heading);
 954      div.appendChild(heading);
 955
 956      while (node)
 957      {
 958        if (node.nodeType == 1 &&    // an element
 959             (node.nodeName == "H1" ||
 960              node.nodeName == "h1" ||
 961              node.nodeName == "DIV" ||
 962              node.nodeName == "div"))
 963          break;
 964
 965        next = node.nextSibling;
 966        node = document.body.removeChild(node);
 967        div.appendChild(node);
 968        node = next;
 969      } 
 970    }
 971  },
 972
 973// return new array of all slides
 974  collect_slides: function () {
 975    var slides = new Array();
 976    var divs = document.body.getElementsByTagName("div");
 977
 978    for (var i = 0; i < divs.length; ++i)
 979    {
 980      div = divs.item(i);
 981
 982      if (this.has_class(div, "slide"))
 983      {
 984        // add slide to collection
 985        slides[slides.length] = div;
 986
 987        // hide each slide as it is found
 988        this.add_class(div, "hidden");
 989
 990        // add dummy <br/> at end for scrolling hack
 991        var node1 = document.createElement("br");
 992        div.appendChild(node1);
 993        var node2 = document.createElement("br");
 994        div.appendChild(node2);
 995      }
 996      else if (this.has_class(div, "background"))
 997      {  // work around for Firefox SVG reload bug
 998        // which otherwise replaces 1st SVG graphic with 2nd
 999        div.style.display = "block";
1000      }
1001    }
1002
1003    this.slides = slides;
1004  },
1005
1006  // return new array of all <div class="handout">
1007  collect_notes: function () {
1008    var notes = new Array();
1009    var divs = document.body.getElementsByTagName("div");
1010
1011    for (var i = 0; i < divs.length; ++i)
1012    {
1013      div = divs.item(i);
1014
1015      if (this.has_class(div, "handout"))
1016      {
1017        // add note to collection
1018        notes[notes.length] = div;
1019
1020        // and hide it
1021        this.add_class(div, "hidden");
1022      }
1023    }
1024
1025    this.notes = notes;
1026  },
1027
1028  // return new array of all <div class="background">
1029  // including named backgrounds e.g. class="background titlepage"
1030  collect_backgrounds: function () {
1031    var backgrounds = new Array();
1032    var divs = document.body.getElementsByTagName("div");
1033
1034    for (var i = 0; i < divs.length; ++i)
1035    {
1036      div = divs.item(i);
1037
1038      if (this.has_class(div, "background"))
1039      {
1040        // add background to collection
1041        backgrounds[backgrounds.length] = div;
1042
1043        // and hide it
1044        this.add_class(div, "hidden");
1045      }
1046    }
1047
1048    this.backgrounds = backgrounds;
1049  },
1050
1051  // set click handlers on all anchors
1052  patch_anchors: function () {
1053    var self = w3c_slidy;
1054    var handler = function (event) {
1055      // compare this.href with location.href
1056      // for link to another slide in this doc
1057
1058      if (self.page_address(this.href) == self.page_address(location.href))
1059      {
1060        // yes, so find new slide number
1061        var newslidenum = self.find_slide_number(this.href);
1062
1063        if (newslidenum != self.slide_number)
1064        {
1065          var slide = self.slides[self.slide_number];
1066          self.hide_slide(slide);
1067          self.slide_number = newslidenum;
1068          slide = self.slides[self.slide_number];
1069          self.show_slide(slide);
1070          self.set_location();
1071        }
1072      }
1073      else
1074        w3c_slidy.stop_propagation(event);
1075
1076//      else if (this.target == null)
1077//        location.href = this.href;
1078
1079      this.blur();
1080      self.disable_slide_click = true;
1081    };
1082
1083    var anchors = document.body.getElementsByTagName("a");
1084
1085    for (var i = 0; i < anchors.length; ++i)
1086    {
1087      if (window.addEventListener)
1088        anchors[i].addEventListener("click", handler, false);
1089      else
1090        anchors[i].attachEvent("onclick", handler);
1091    }
1092  },
1093
1094  // ### CHECK ME ### see which functions are invoked via setTimeout
1095  // either directly or indirectly for use of w3c_slidy vs this
1096  show_slide_number: function () {
1097    var timer = w3c_slidy.get_timer();
1098    w3c_slidy.slide_number_element.innerHTML = timer + w3c_slidy.localize("slide") + " " +
1099           (w3c_slidy.slide_number + 1) + "/" + w3c_slidy.slides.length;
1100  },
1101
1102  // every 200mS check if the location has been changed as a
1103  // result of the user activating the Back button/menu item
1104  // doesn't work for Opera < 9.5
1105  check_location: function () {
1106    var hash = location.hash;
1107
1108    if (w3c_slidy.slide_number > 0 && (hash == "" || hash == "#"))
1109      w3c_slidy.goto_slide(0);
1110    else if (hash.length > 2 && hash != "#("+(w3c_slidy.slide_number+1)+")")
1111    {
1112      var num = parseInt(location.hash.substr(2));
1113
1114      if (!isNaN(num))
1115        w3c_slidy.goto_slide(num-1);
1116    }
1117
1118    if (w3c_slidy.time_left && w3c_slidy.slide_number > 0)
1119    {
1120      w3c_slidy.show_slide_number();
1121
1122      if (w3c_slidy.time_left > 0)
1123        w3c_slidy.time_left -= 200;
1124    } 
1125  },
1126
1127  get_timer: function () {
1128    var timer = "";
1129    if (w3c_slidy.time_left)
1130    {
1131      var mins, secs;
1132      secs = Math.floor(w3c_slidy.time_left/1000);
1133      mins = Math.floor(secs / 60);
1134      secs = secs % 60;
1135      timer = (mins ? mins+"m" : "") + secs + "s ";
1136    }
1137
1138    return timer;
1139  },
1140
1141  // this doesn't push location onto history stack for IE
1142  // for which a hidden iframe hack is needed: load page into
1143  // the iframe with script that set's parent's location.hash
1144  // but that won't work for standalone use unless we can
1145  // create the page dynamically via a javascript: URL
1146  set_location: function () {
1147     var uri = w3c_slidy.page_address(location.href);
1148     var hash = "#(" + (w3c_slidy.slide_number+1) + ")";
1149
1150     if (w3c_slidy.slide_number >= 0)
1151       uri = uri + hash;
1152
1153     if (w3c_slidy.ie && (w3c_slidy.ie6 || w3c_slidy.ie7))
1154       w3c_slidy.push_hash(hash);
1155
1156     if (uri != location.href) // && !khtml
1157        location.href = uri;
1158
1159     if (this.khtml)
1160        hash = "(" + (w3c_slidy.slide_number+1) + ")";
1161
1162     if (!this.ie && location.hash != hash && location.hash != "")
1163       location.hash = hash;
1164
1165     document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
1166     w3c_slidy.show_slide_number();
1167  },
1168
1169  page_address: function (uri) {
1170    var i = uri.indexOf("#");
1171
1172    if (i < 0)
1173      i = uri.indexOf("%23");
1174
1175    // check if anchor is entire page
1176
1177    if (i < 0)
1178      return uri;  // yes
1179
1180    return uri.substr(0, i);
1181  },
1182
1183  // only used for IE6 and IE7
1184  on_frame_loaded: function (hash) {
1185    location.hash = hash;
1186    var uri = w3c_slidy.page_address(location.href);
1187    location.href = uri + hash;
1188  },
1189
1190  // history hack with thanks to Bertrand Le Roy
1191  push_hash: function (hash) {
1192    if (hash == "") hash = "#(1)";
1193      window.location.hash = hash;
1194
1195    var doc = document.getElementById("historyFrame").contentWindow.document;
1196    doc.open("javascript:'<html></html>'");
1197    doc.write("<html><head><script type=\"text/javascript\">window.parent.w3c_slidy.on_frame_loaded('"+
1198      (hash) + "');</script></head><body>hello mum</body></html>");
1199      doc.close();
1200  },
1201
1202  // find current slide based upon location
1203  // first find target anchor and then look
1204  // for associated div element enclosing it
1205  // finally map that to slide number
1206  find_slide_number: function (uri) {
1207    // first get anchor from page location
1208
1209    var i = uri.indexOf("#");
1210
1211    // check if anchor is entire page
1212    if (i < 0)
1213      return 0;  // yes
1214
1215    var anchor = unescape(uri.substr(i+1));
1216
1217    // now use anchor as XML ID to find target
1218    var target = document.getElementById(anchor);
1219
1220    if (!target)
1221    {
1222      // does anchor look like "(2)" for slide 2 ??
1223      // where first slide is (1)
1224      var re = /\((\d)+\)/;
1225
1226      if (anchor.match(re))
1227      {
1228        var num = parseInt(anchor.substring(1, anchor.length-1));
1229
1230        if (num > this.slides.length)
1231          num = 1;
1232
1233        if (--num < 0)
1234          num = 0;
1235
1236        return num;
1237      }
1238
1239      // accept [2] for backwards compatibility
1240      re = /\[(\d)+\]/;
1241
1242      if (anchor.match(re))
1243      {
1244         var num = parseInt(anchor.substring(1, anchor.length-1));
1245
1246         if (num > this.slides.length)
1247            num = 1;
1248
1249         if (--num < 0)
1250            num = 0;
1251
1252         return num;
1253      }
1254
1255      // oh dear unknown anchor
1256      return 0;
1257    }
1258
1259    // search for enclosing slide
1260
1261    while (true)
1262    {
1263      // browser coerces html elements to uppercase!
1264      if (target.nodeName.toLowerCase() == "div" &&
1265            this.has_class(target, "slide"))
1266      {
1267        // found the slide element
1268        break;
1269      }
1270
1271      // otherwise try parent element if any
1272
1273      target = target.parentNode;
1274
1275      if (!target)
1276      {
1277        return 0;   // no luck!
1278      }
1279    };
1280
1281    for (i = 0; i < slides.length; ++i)
1282    {
1283      if (slides[i] == target)
1284        return i;  // success
1285    }
1286
1287    // oh dear still no luck
1288    return 0;
1289  },
1290
1291  previous_slide: function (incremental) {
1292    if (!w3c_slidy.view_all)
1293    {
1294      var slide;
1295
1296      if ((incremental || w3c_slidy.slide_number == 0) && w3c_slidy.last_shown != null)
1297      {
1298        w3c_slidy.last_shown = w3c_slidy.hide_previous_item(w3c_slidy.last_shown);
1299        w3c_slidy.set_eos_status(false);
1300      }
1301      else if (w3c_slidy.slide_number > 0)
1302      {
1303        slide = w3c_slidy.slides[w3c_slidy.slide_number];
1304        w3c_slidy.hide_slide(slide);
1305
1306        w3c_slidy.slide_number = w3c_slidy.slide_number - 1;
1307        slide = w3c_slidy.slides[w3c_slidy.slide_number];
1308        w3c_slidy.set_visibility_all_incremental("visible");
1309        w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1310        w3c_slidy.set_eos_status(true);
1311        w3c_slidy.show_slide(slide);
1312      }
1313
1314      w3c_slidy.set_location();
1315
1316      if (!w3c_slidy.ns_pos)
1317        w3c_slidy.refresh_toolbar(200);
1318    }
1319  },
1320
1321  next_slide: function (incremental) {
1322    if (!w3c_slidy.view_all)
1323    {
1324      var slide, last = w3c_slidy.last_shown;
1325
1326      if (incremental || w3c_slidy.slide_number == w3c_slidy.slides.length - 1)
1327         w3c_slidy.last_shown = w3c_slidy.reveal_next_item(w3c_slidy.last_shown);
1328
1329      if ((!incremental || w3c_slidy.last_shown == null) &&
1330             w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
1331      {
1332         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1333         w3c_slidy.hide_slide(slide);
1334
1335         w3c_slidy.slide_number = w3c_slidy.slide_number + 1;
1336         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1337         w3c_slidy.last_shown = null;
1338         w3c_slidy.set_visibility_all_incremental("hidden");
1339         w3c_slidy.show_slide(slide);
1340      }
1341      else if (!w3c_slidy.last_shown)
1342      {
1343         if (last && incremental)
1344           w3c_slidy.last_shown = last;
1345      }
1346
1347      w3c_slidy.set_location();
1348
1349      w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1350
1351      if (!w3c_slidy.ns_pos)
1352         w3c_slidy.refresh_toolbar(200);
1353     }
1354  },
1355
1356  // to first slide with nothing revealed
1357  // i.e. state at start of presentation
1358  first_slide: function () {
1359     if (!w3c_slidy.view_all)
1360     {
1361       var slide;
1362
1363       if (w3c_slidy.slide_number != 0)
1364       {
1365         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1366         w3c_slidy.hide_slide(slide);
1367
1368         w3c_slidy.slide_number = 0;
1369         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1370         w3c_slidy.last_shown = null;
1371         w3c_slidy.set_visibility_all_incremental("hidden");
1372         w3c_slidy.show_slide(slide);
1373       }
1374
1375       w3c_slidy.set_eos_status(
1376         !w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1377       w3c_slidy.set_location();
1378     }
1379  },
1380
1381  // goto last slide with everything revealed
1382  // i.e. state at end of presentation
1383  last_slide: function () {
1384    if (!w3c_slidy.view_all)
1385    {
1386      var slide;
1387
1388      w3c_slidy.last_shown = null; //revealNextItem(lastShown);
1389
1390      if (w3c_slidy.last_shown == null &&
1391          w3c_slidy.slide_number < w3c_slidy.slides.length - 1)
1392      {
1393         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1394         w3c_slidy.hide_slide(slide);
1395         w3c_slidy.slide_number = w3c_slidy.slides.length - 1;
1396         slide = w3c_slidy.slides[w3c_slidy.slide_number];
1397         w3c_slidy.set_visibility_all_incremental("visible");
1398         w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1399
1400         w3c_slidy.show_slide(slide);
1401      }
1402      else
1403      {
1404         w3c_slidy.set_visibility_all_incremental("visible");
1405         w3c_slidy.last_shown = w3c_slidy.previous_incremental_item(null);
1406      }
1407
1408      w3c_slidy.set_eos_status(true);
1409      w3c_slidy.set_location();
1410    }
1411  },
1412
1413
1414  // ### check this and consider add/remove class
1415  set_eos_status: function (state) {
1416    if (this.eos)
1417      this.eos.style.color = (state ? "rgb(240,240,240)" : "red");
1418  },
1419
1420  // first slide is 0
1421  goto_slide: function (num) {
1422    //alert("going to slide " + (num+1));
1423    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1424    w3c_slidy.hide_slide(slide);
1425    w3c_slidy.slide_number = num;
1426    slide = w3c_slidy.slides[w3c_slidy.slide_number];
1427    w3c_slidy.last_shown = null;
1428    w3c_slidy.set_visibility_all_incremental("hidden");
1429    w3c_slidy.set_eos_status(!w3c_slidy.next_incremental_item(w3c_slidy.last_shown));
1430    document.title = w3c_slidy.title + " (" + (w3c_slidy.slide_number+1) + ")";
1431    w3c_slidy.show_slide(slide);
1432    w3c_slidy.show_slide_number();
1433  },
1434
1435
1436  show_slide: function (slide) {
1437    this.sync_background(slide);
1438    window.scrollTo(0,0);
1439    this.remove_class(slide, "hidden");
1440  },
1441
1442  hide_slide: function (slide) {
1443    this.add_class(slide, "hidden");
1444  },
1445
1446  // show just the backgrounds pertinent to this slide
1447  // when slide background-color is transparent
1448  // this should now work with rgba color values
1449  sync_background: function (slide) {
1450    var background;
1451    var bgColor;
1452
1453    if (slide.currentStyle)
1454      bgColor = slide.currentStyle["backgroundColor"];
1455    else if (document.defaultView)
1456    {
1457      var styles = document.defaultView.getComputedStyle(slide,null);
1458
1459      if (styles)
1460        bgColor = styles.getPropertyValue("background-color");
1461      else // broken implementation probably due Safari or Konqueror
1462      {
1463        //alert("defective implementation of getComputedStyle()");
1464        bgColor = "transparent";
1465      }
1466    }
1467    else
1468      bgColor == "transparent";
1469
1470    if (bgColor == "transparent" ||
1471        bgColor.indexOf("rgba") >= 0 ||
1472        bgColor.indexOf("opacity") >= 0)
1473    {
1474      var slideClass = this.get_class_list(slide);
1475
1476      for (var i = 0; i < this.backgrounds.length; i++)
1477      {
1478        background = this.backgrounds[i];
1479
1480        var bgClass = this.get_class_list(background);
1481
1482        if (this.matching_background(slideClass, bgClass))
1483          this.remove_class(background, "hidden");
1484        else
1485          this.add_class(background, "hidden");
1486      }
1487    }
1488    else // forcibly hide all backgrounds
1489      this.hide_backgrounds();
1490  },
1491
1492  hide_backgrounds: function () {
1493    for (var i = 0; i < this.backgrounds.length; i++)
1494    {
1495      background = this.backgrounds[i];
1496      this.add_class(background, "hidden");
1497    }
1498  },
1499
1500  // compare classes for slide and background
1501  matching_background: function (slideClass, bgClass) {
1502    var i, count, pattern, result;
1503
1504    // define pattern as regular expression
1505    pattern = /\w+/g;
1506
1507    // check background class names
1508    result = bgClass.match(pattern);
1509
1510    for (i = count = 0; i < result.length; i++)
1511    {
1512      if (result[i] == "hidden")
1513        continue;
1514
1515      if (result[i] == "background")
1516	continue;
1517
1518      ++count;
1519    }
1520
1521    if (count == 0)  // default match
1522      return true;
1523
1524    // check for matches and place result in array
1525    result = slideClass.match(pattern);
1526
1527    // now check if desired name is present for background
1528    for (i = count = 0; i < result.length; i++)
1529    {
1530      if (result[i] == "hidden")
1531        continue;
1532
1533      if (this.has_token(bgClass, result[i]))
1534        return true;
1535    }
1536
1537    return false;
1538  },
1539
1540  resized: function () {
1541     var width = 0;
1542
1543     if ( typeof( window.innerWidth ) == 'number' )
1544       width = window.innerWidth;  // Non IE browser
1545     else if (document.documentElement && document.documentElement.clientWidth)
1546       width = document.documentElement.clientWidth;  // IE6
1547     else if (document.body && document.body.clientWidth)
1548       width = document.body.clientWidth; // IE4
1549
1550     var height = 0;
1551
1552     if ( typeof( window.innerHeight ) == 'number' )
1553       height = window.innerHeight;  // Non IE browser
1554     else if (document.documentElement && document.documentElement.clientHeight)
1555       height = document.documentElement.clientHeight;  // IE6
1556     else if (document.body && document.body.clientHeight)
1557       height = document.body.clientHeight; // IE4
1558
1559     if (height && (width/height > 1.05*1024/768))
1560     {
1561       width = height * 1024.0/768;
1562     }
1563
1564     // IE fires onresize even when only font size is changed!
1565     // so we do a check to avoid blocking < and > actions
1566     if (width != w3c_slidy.last_width || height != w3c_slidy.last_height)
1567     {
1568       if (width >= 1100)
1569         w3c_slidy.size_index = 5;    // 4
1570       else if (width >= 1000)
1571         w3c_slidy.size_index = 4;    // 3
1572       else if (width >= 800)
1573         w3c_slidy.size_index = 3;    // 2
1574       else if (width >= 600)
1575         w3c_slidy.size_index = 2;    // 1
1576       else if (width)
1577         w3c_slidy.size_index = 0;
1578
1579       // add in font size adjustment from meta element e.g.
1580       // <meta name="font-size-adjustment" content="-2" />
1581       // useful when slides have too much content ;-)
1582
1583       if (0 <= w3c_slidy.size_index + w3c_slidy.size_adjustment &&
1584             w3c_slidy.size_index + w3c_slidy.size_adjustment < w3c_slidy.sizes.length)
1585         w3c_slidy.size_index = w3c_slidy.size_index + w3c_slidy.size_adjustment;
1586
1587       // enables cross browser use of relative width/height
1588       // on object elements for use with SVG and Flash media
1589       w3c_slidy.adjust_object_dimensions(width, height);
1590
1591       if (document.body.style.fontSize != w3c_slidy.sizes[w3c_slidy.size_index])
1592       {
1593         document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1594       }
1595
1596       w3c_slidy.last_width = width;
1597       w3c_slidy.last_height = height;
1598
1599       // force reflow to work around Mozilla bug
1600       if (w3c_slidy.ns_pos)
1601       {
1602         var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1603         w3c_slidy.hide_slide(slide);
1604         w3c_slidy.show_slide(slide);
1605       }
1606
1607       // force correct positioning of toolbar
1608       w3c_slidy.refresh_toolbar(200);
1609     }
1610  },
1611
1612  scrolled: function () {
1613    if (w3c_slidy.toolbar && !w3c_slidy.ns_pos && !w3c_slidy.ie7)
1614    {
1615      w3c_slidy.hack_offset = w3c_slidy.scroll_x_offset();
1616      // hide toolbar
1617      w3c_slidy.toolbar.style.display = "none";
1618
1619      // make it reappear later
1620      if (w3c_slidy.scrollhack == 0 && !w3c_slidy.view_all)
1621      {
1622        setTimeout(function () {w3c_slidy.show_toolbar(); }, 1000);
1623        w3c_slidy.scrollhack = 1;
1624      }
1625    }
1626  },
1627
1628  hide_toolbar: function () {
1629    w3c_slidy.add_class(w3c_slidy.toolbar, "hidden");
1630    window.focus();
1631  },
1632
1633  // used to ensure IE refreshes toolbar in correct position
1634  refresh_toolbar: function (interval) {
1635    if (!w3c_slidy.ns_pos && !w3c_slidy.ie7)
1636    {
1637      w3c_slidy.hide_toolbar();
1638      setTimeout(function () {w3c_slidy.show_toolbar(); }, interval);
1639    }
1640  },
1641
1642  // restores toolbar after short delay
1643  show_toolbar: function () {
1644    if (w3c_slidy.want_toolbar)
1645    {
1646      w3c_slidy.toolbar.style.display = "block";
1647
1648      if (!w3c_slidy.ns_pos)
1649      {
1650        // adjust position to allow for scrolling
1651        var xoffset = w3c_slidy.scroll_x_offset();
1652        w3c_slidy.toolbar.style.left = xoffset;
1653        w3c_slidy.toolbar.style.right = xoffset;
1654
1655        // determine vertical scroll offset
1656        //var yoffset = scrollYOffset();
1657
1658        // bottom is doc height - window height - scroll offset
1659        //var bottom = documentHeight() - lastHeight - yoffset
1660
1661        //if (yoffset > 0 || documentHeight() > lastHeight)
1662        //   bottom += 16;  // allow for height of scrollbar
1663
1664        w3c_slidy.toolbar.style.bottom = 0; //bottom;
1665      }
1666
1667      w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden");
1668    }
1669
1670    w3c_slidy.scrollhack = 0;
1671
1672
1673    // set the keyboard focus to the help link on the
1674    // toolbar to ensure that document has the focus
1675    // IE doesn't always work with window.focus()
1676    // and this hack has benefit of Enter for help
1677
1678    try
1679    {
1680      if (!w3c_slidy.opera)
1681        w3c_slidy.help_anchor.focus();
1682    }
1683    catch (e)
1684    {
1685    }
1686  },
1687
1688// invoked via F key
1689  toggle_toolbar: function () {
1690    if (!w3c_slidy.view_all)
1691    {
1692      if (w3c_slidy.has_class(w3c_slidy.toolbar, "hidden"))
1693      {
1694        w3c_slidy.remove_class(w3c_slidy.toolbar, "hidden")
1695        w3c_slidy.want_toolbar = 1;
1696      }
1697      else
1698      {
1699        w3c_slidy.add_class(w3c_slidy.toolbar, "hidden")
1700        w3c_slidy.want_toolbar = 0;
1701      }
1702    }
1703  },
1704
1705  scroll_x_offset: function () {
1706    if (window.pageXOffset)
1707      return self.pageXOffset;
1708
1709    if (document.documentElement && 
1710             document.documentElement.scrollLeft)
1711      return document.documentElement.scrollLeft;
1712
1713    if (document.body)
1714      return document.body.scrollLeft;
1715
1716    return 0;
1717  },
1718
1719  scroll_y_offset: function () {
1720    if (window.pageYOffset)
1721      return self.pageYOffset;
1722
1723    if (document.documentElement && 
1724             document.documentElement.scrollTop)
1725      return document.documentElement.scrollTop;
1726
1727    if (document.body)
1728      return document.body.scrollTop;
1729
1730    return 0;
1731  },
1732
1733  // looking for a way to determine height of slide content
1734  // the slide itself is set to the height of the window
1735  optimize_font_size: function () {
1736    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1737
1738    //var dh = documentHeight(); //getDocHeight(document);
1739    var dh = slide.scrollHeight;
1740    var wh = getWindowHeight();
1741    var u = 100 * dh / wh;
1742
1743    alert("window utilization = " + u + "% (doc "
1744      + dh + " win " + wh + ")");
1745  },
1746
1747  // from document object
1748  get_doc_height: function (doc) {
1749    if (!doc)
1750      doc = document;
1751
1752    if (doc && doc.body && doc.body.offsetHeight)
1753      return doc.body.offsetHeight;  // ns/gecko syntax
1754
1755    if (doc && doc.body && doc.body.scrollHeight)
1756      return doc.body.scrollHeight;
1757
1758    alert("couldn't determine document height");
1759  },
1760
1761  get_window_height: function () {
1762    if ( typeof( window.innerHeight ) == 'number' )
1763      return window.innerHeight;  // Non IE browser
1764
1765    if (document.documentElement && document.documentElement.clientHeight)
1766      return document.documentElement.clientHeight;  // IE6
1767
1768    if (document.body && document.body.clientHeight)
1769      return document.body.clientHeight; // IE4
1770  },
1771
1772  document_height: function () {
1773    var sh, oh;
1774
1775    sh = document.body.scrollHeight;
1776    oh = document.body.offsetHeight;
1777
1778    if (sh && oh)
1779    {
1780      return (sh > oh ? sh : oh);
1781    }
1782
1783    // no idea!
1784    return 0;
1785  },
1786
1787  smaller: function () {
1788    if (w3c_slidy.size_index > 0)
1789    {
1790      --w3c_slidy.size_index;
1791    }
1792
1793    w3c_slidy.toolbar.style.display = "none";
1794    document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1795    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1796    w3c_slidy.hide_slide(slide);
1797    w3c_slidy.show_slide(slide);
1798    setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
1799  },
1800
1801  bigger: function () {
1802    if (w3c_slidy.size_index < w3c_slidy.sizes.length - 1)
1803    {
1804      ++w3c_slidy.size_index;
1805    }
1806
1807    w3c_slidy.toolbar.style.display = "none";
1808    document.body.style.fontSize = w3c_slidy.sizes[w3c_slidy.size_index];
1809    var slide = w3c_slidy.slides[w3c_slidy.slide_number];
1810    w3c_slidy.hide_slide(slide);
1811    w3c_slidy.show_slide(slide);
1812    setTimeout(function () {w3c_slidy.show_toolbar(); }, 50);
1813  },
1814
1815  // enables cross browser use of relative width/height
1816  // on object elements for use with SVG and Flash media
1817  // with thanks to Ivan Herman for the suggestion
1818  adjust_object_dimensions: function (width, height) {
1819    for( var i

Large files files are truncated, but you can click here to view the full file