source: rtems-tools/doc/asciidoc/javascripts/slidy.js @ f91e023

4.104.115
Last change on this file since f91e023 was f91e023, checked in by Chris Johns <chrisj@…>, on 02/17/14 at 07:04:46

Add the documentation.

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