1 // S5 v1.1 slides.js -- released into the Public Domain
3 // Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information
4 // about all the wonderful and talented contributors to this code!
13 var defaultView
= 'slideshow';
14 var controlVis
= 'visible';
16 var isIE
= navigator
.appName
== 'Microsoft Internet Explorer' ? 1 : 0;
17 var isOp
= navigator
.userAgent
.indexOf('Opera') > -1 ? 1 : 0;
18 var isGe
= navigator
.userAgent
.indexOf('Gecko') > -1 && navigator
.userAgent
.indexOf('Safari') < 1 ? 1 : 0;
20 function hasClass(object
, className
) {
21 if (!object
.className
) return false;
22 return (object
.className
.search('(^|\\s)' + className
+ '(\\s|$)') != -1);
25 function hasValue(object
, value
) {
26 if (!object
) return false;
27 return (object
.search('(^|\\s)' + value
+ '(\\s|$)') != -1);
30 function removeClass(object
,className
) {
32 object
.className
= object
.className
.replace(new RegExp('(^|\\s)'+className
+'(\\s|$)'), RegExp
.$1+RegExp
.$2);
35 function addClass(object
,className
) {
36 if (!object
|| hasClass(object
, className
)) return;
37 if (object
.className
) {
38 object
.className
+= ' '+className
;
40 object
.className
= className
;
44 function GetElementsWithClassName(elementName
,className
) {
45 var allElements
= document
.getElementsByTagName(elementName
);
46 var elemColl
= new Array();
47 for (var i
= 0; i
< allElements
.length
; i
++) {
48 if (hasClass(allElements
[i
], className
)) {
49 elemColl
[elemColl
.length
] = allElements
[i
];
55 function isParentOrSelf(element
, id
) {
56 if (element
== null || element
.nodeName
=='BODY') return false;
57 else if (element
.id
== id
) return true;
58 else return isParentOrSelf(element
.parentNode
, id
);
61 function nodeValue(node
) {
63 if (node
.nodeType
== 1) {
64 var children
= node
.childNodes
;
65 for (var i
= 0; i
< children
.length
; ++i
) {
66 result
+= nodeValue(children
[i
]);
69 else if (node
.nodeType
== 3) {
70 result
= node
.nodeValue
;
75 function slideLabel() {
76 var slideColl
= GetElementsWithClassName('*','slide');
77 var list
= document
.getElementById('jumplist');
78 smax
= slideColl
.length
;
79 for (var n
= 0; n
< smax
; n
++) {
80 var obj
= slideColl
[n
];
82 var did
= 'slide' + n
.toString();
83 obj
.setAttribute('id',did
);
87 var menu
= obj
.firstChild
;
88 if (!menu
) continue; // to cope with empty slides
89 while (menu
&& menu
.nodeType
== 3) {
90 menu
= menu
.nextSibling
;
92 if (!menu
) continue; // to cope with slides with only text nodes
94 var menunodes
= menu
.childNodes
;
95 for (var o
= 0; o
< menunodes
.length
; o
++) {
96 otext
+= nodeValue(menunodes
[o
]);
98 list
.options
[list
.length
] = new Option(n
+ ' : ' + otext
, n
);
102 function currentSlide() {
104 if (document
.getElementById
) {
105 cs
= document
.getElementById('currentSlide');
107 cs
= document
.currentSlide
;
109 cs
.innerHTML
= '<span id="csHere">' + snum
+ '<\/span> ' +
110 '<span id="csSep">\/<\/span> ' +
111 '<span id="csTotal">' + (smax
-1) + '<\/span>';
113 cs
.style
.visibility
= 'hidden';
115 cs
.style
.visibility
= 'visible';
120 if (document
.getElementById('slideProj').disabled
|| step
== 0) return;
121 var jl
= document
.getElementById('jumplist');
122 var cid
= 'slide' + snum
;
123 var ce
= document
.getElementById(cid
);
124 if (incrementals
[snum
].length
> 0) {
125 for (var i
= 0; i
< incrementals
[snum
].length
; i
++) {
126 removeClass(incrementals
[snum
][i
], 'current');
127 removeClass(incrementals
[snum
][i
], 'incremental');
133 if (snum
> lmax
) snum
= lmax
;
134 if (snum
< 0) snum
= 0;
136 snum
= parseInt(jl
.value
);
137 var nid
= 'slide' + snum
;
138 var ne
= document
.getElementById(nid
);
140 ne
= document
.getElementById('slide0');
143 if (step
< 0) {incpos
= incrementals
[snum
].length
} else {incpos
= 0;}
144 if (incrementals
[snum
].length
> 0 && incpos
== 0) {
145 for (var i
= 0; i
< incrementals
[snum
].length
; i
++) {
146 if (hasClass(incrementals
[snum
][i
], 'current'))
149 addClass(incrementals
[snum
][i
], 'incremental');
152 if (incrementals
[snum
].length
> 0 && incpos
> 0)
153 addClass(incrementals
[snum
][incpos
- 1], 'current');
154 ce
.style
.visibility
= 'hidden';
155 ne
.style
.visibility
= 'visible';
156 jl
.selectedIndex
= snum
;
161 function goTo(target
) {
162 if (target
>= smax
|| target
== snum
) return;
166 function subgo(step
) {
168 removeClass(incrementals
[snum
][incpos
- 1],'current');
169 removeClass(incrementals
[snum
][incpos
], 'incremental');
170 addClass(incrementals
[snum
][incpos
],'current');
174 removeClass(incrementals
[snum
][incpos
],'current');
175 addClass(incrementals
[snum
][incpos
], 'incremental');
176 addClass(incrementals
[snum
][incpos
- 1],'current');
181 var slideColl
= GetElementsWithClassName('*','slide');
182 var slides
= document
.getElementById('slideProj');
183 var outline
= document
.getElementById('outlineStyle');
184 if (!slides
.disabled
) {
185 slides
.disabled
= true;
186 outline
.disabled
= false;
189 for (var n
= 0; n
< smax
; n
++) {
190 var slide
= slideColl
[n
];
191 slide
.style
.visibility
= 'visible';
194 slides
.disabled
= false;
195 outline
.disabled
= true;
198 for (var n
= 0; n
< smax
; n
++) {
199 var slide
= slideColl
[n
];
200 slide
.style
.visibility
= 'hidden';
202 slideColl
[snum
].style
.visibility
= 'visible';
206 function showHide(action
) {
207 var obj
= GetElementsWithClassName('*','hideme')[0];
209 case 's': obj
.style
.visibility
= 'visible'; break;
210 case 'h': obj
.style
.visibility
= 'hidden'; break;
212 if (obj
.style
.visibility
!= 'visible') {
213 obj
.style
.visibility
= 'visible';
215 obj
.style
.visibility
= 'hidden';
221 // 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
225 key
.which
= key
.keyCode
;
227 if (key
.which
== 84) {
235 if (window
.event
&& isParentOrSelf(window
.event
.srcElement
, 'controls')) return;
236 if (key
.target
&& isParentOrSelf(key
.target
, 'controls')) return;
237 if(number
!= undef
) {
242 case 34: // page down
245 if(number
!= undef
) {
247 } else if (!incrementals
[snum
] || incpos
>= incrementals
[snum
].length
) {
256 if(number
!= undef
) {
258 } else if (!incrementals
[snum
] || incpos
<= 0) {
274 if (key
.which
< 48 || key
.which
> 57) {
277 if (window
.event
&& isParentOrSelf(window
.event
.srcElement
, 'controls')) return;
278 if (key
.target
&& isParentOrSelf(key
.target
, 'controls')) return;
279 number
= (((number
!= undef
) ? number
: 0) * 10) + (key
.which
- 48);
285 function clicker(e
) {
289 target
= window
.event
.srcElement
;
291 } else target
= e
.target
;
292 if (target
.getAttribute('href') != null || hasValue(target
.rel
, 'external') || isParentOrSelf(target
, 'controls') || isParentOrSelf(target
,'embed') || isParentOrSelf(target
,'object')) return true;
293 if (!e
.which
|| e
.which
== 1) {
294 if (!incrementals
[snum
] || incpos
>= incrementals
[snum
].length
) {
302 function findSlide(hash
) {
304 var slides
= GetElementsWithClassName('*','slide');
305 for (var i
= 0; i
< slides
.length
; i
++) {
306 var targetSlide
= slides
[i
];
307 if ( (targetSlide
.name
&& targetSlide
.name
== hash
)
308 || (targetSlide
.id
&& targetSlide
.id
== hash
) ) {
309 target
= targetSlide
;
313 while(target
!= null && target
.nodeName
!= 'BODY') {
314 if (hasClass(target
, 'slide')) {
315 return parseInt(target
.id
.slice(5));
317 target
= target
.parentNode
;
322 function slideJump() {
323 if (window
.location
.hash
== null) return;
324 var sregex
= /^#slide(\d+)$/;
325 var matches
= sregex
.exec(window
.location
.hash
);
327 if (matches
!= null) {
328 dest
= parseInt(matches
[1]);
330 dest
= findSlide(window
.location
.hash
.slice(1));
336 function fixLinks() {
337 var thisUri
= window
.location
.href
;
338 thisUri
= thisUri
.slice(0, thisUri
.length
- window
.location
.hash
.length
);
339 var aelements
= document
.getElementsByTagName('A');
340 for (var i
= 0; i
< aelements
.length
; i
++) {
341 var a
= aelements
[i
].href
;
342 var slideID
= a
.match('\#slide[0-9]{1,2}');
343 if ((slideID
) && (slideID
[0].slice(0,1) == '#')) {
344 var dest
= findSlide(slideID
[0].slice(1));
346 if (aelements
[i
].addEventListener
) {
347 aelements
[i
].addEventListener("click", new Function("e",
348 "if (document.getElementById('slideProj').disabled) return;" +
349 "go("+dest
+" - snum); " +
350 "if (e.preventDefault) e.preventDefault();"), true);
351 } else if (aelements
[i
].attachEvent
) {
352 aelements
[i
].attachEvent("onclick", new Function("",
353 "if (document.getElementById('slideProj').disabled) return;" +
354 "go("+dest
+" - snum); " +
355 "event.returnValue = false;"));
362 function externalLinks() {
363 if (!document
.getElementsByTagName
) return;
364 var anchors
= document
.getElementsByTagName('a');
365 for (var i
=0; i
<anchors
.length
; i
++) {
366 var anchor
= anchors
[i
];
367 if (anchor
.getAttribute('href') && hasValue(anchor
.rel
, 'external')) {
368 anchor
.target
= '_blank';
369 addClass(anchor
,'external');
374 function createControls() {
375 var controlsDiv
= document
.getElementById("controls");
376 if (!controlsDiv
) return;
377 var hider
= ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
378 var hideDiv
, hideList
= '';
379 if (controlVis
== 'hidden') {
384 controlsDiv
.innerHTML
= '<form action="#" id="controlForm"' + hideDiv
+ '>' +
385 '<div id="navLinks">' +
386 '<a accesskey="t" id="toggle" href="javascript:toggle();">Ø<\/a>' +
387 '<a accesskey="z" id="prev" href="javascript:go(-1);">«<\/a>' +
388 '<a accesskey="x" id="next" href="javascript:go(1);">»<\/a>' +
389 '<div id="navList"' + hideList
+ '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
391 if (controlVis
== 'hidden') {
392 var hidden
= document
.getElementById('navLinks');
394 var hidden
= document
.getElementById('jumplist');
396 addClass(hidden
,'hideme');
399 function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
400 if (!s5mode
) return false;
401 var vScale
= 22; // both yield 32 (after rounding) at 1024x768
402 var hScale
= 32; // perhaps should auto-calculate based on theme's declared value?
403 if (window
.innerHeight
) {
404 var vSize
= window
.innerHeight
;
405 var hSize
= window
.innerWidth
;
406 } else if (document
.documentElement
.clientHeight
) {
407 var vSize
= document
.documentElement
.clientHeight
;
408 var hSize
= document
.documentElement
.clientWidth
;
409 } else if (document
.body
.clientHeight
) {
410 var vSize
= document
.body
.clientHeight
;
411 var hSize
= document
.body
.clientWidth
;
413 var vSize
= 700; // assuming 1024x768, minus chrome and such
414 var hSize
= 1024; // these do not account for kiosk mode or Opera Show
416 var newSize
= Math
.min(Math
.round(vSize
/vScale),Math.round(hSize/hScale
));
417 fontSize(newSize
+ 'px');
418 if (isGe
) { // hack to counter incremental reflow bugs
419 var obj
= document
.getElementsByTagName('body')[0];
420 obj
.style
.display
= 'none';
421 obj
.style
.display
= 'block';
425 function fontSize(value
) {
426 if (!(s5ss
= document
.getElementById('s5ss'))) {
428 document
.getElementsByTagName('head')[0].appendChild(s5ss
= document
.createElement('style'));
429 s5ss
.setAttribute('media','screen, projection');
430 s5ss
.setAttribute('id','s5ss');
432 document
.createStyleSheet();
433 document
.s5ss
= document
.styleSheets
[document
.styleSheets
.length
- 1];
437 while (s5ss
.lastChild
) s5ss
.removeChild(s5ss
.lastChild
);
438 s5ss
.appendChild(document
.createTextNode('body {font-size: ' + value
+ ' !important;}'));
440 document
.s5ss
.addRule('body','font-size: ' + value
+ ' !important;');
444 function notOperaFix() {
445 slideCSS
= document
.getElementById('slideProj').href
;
446 var slides
= document
.getElementById('slideProj');
447 var outline
= document
.getElementById('outlineStyle');
448 slides
.setAttribute('media','screen');
449 outline
.disabled
= true;
451 slides
.setAttribute('href','null'); // Gecko fix
452 slides
.setAttribute('href',slideCSS
); // Gecko fix
454 if (isIE
&& document
.styleSheets
&& document
.styleSheets
[0]) {
455 document
.styleSheets
[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
456 document
.styleSheets
[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
457 document
.styleSheets
[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
461 function getIncrementals(obj
) {
462 var incrementals
= new Array();
465 var children
= obj
.childNodes
;
466 for (var i
= 0; i
< children
.length
; i
++) {
467 var child
= children
[i
];
468 if (hasClass(child
, 'incremental')) {
469 if (child
.nodeName
== 'OL' || child
.nodeName
== 'UL') {
470 removeClass(child
, 'incremental');
471 for (var j
= 0; j
< child
.childNodes
.length
; j
++) {
472 if (child
.childNodes
[j
].nodeType
== 1) {
473 addClass(child
.childNodes
[j
], 'incremental');
477 incrementals
[incrementals
.length
] = child
;
478 removeClass(child
,'incremental');
481 if (hasClass(child
, 'show-first')) {
482 if (child
.nodeName
== 'OL' || child
.nodeName
== 'UL') {
483 removeClass(child
, 'show-first');
484 if (child
.childNodes
[isGe
].nodeType
== 1) {
485 removeClass(child
.childNodes
[isGe
], 'incremental');
488 incrementals
[incrementals
.length
] = child
;
491 incrementals
= incrementals
.concat(getIncrementals(child
));
496 function createIncrementals() {
497 var incrementals
= new Array();
498 for (var i
= 0; i
< smax
; i
++) {
499 incrementals
[i
] = getIncrementals(document
.getElementById('slide'+i
));
504 function defaultCheck() {
505 var allMetas
= document
.getElementsByTagName('meta');
506 for (var i
= 0; i
< allMetas
.length
; i
++) {
507 if (allMetas
[i
].name
== 'defaultView') {
508 defaultView
= allMetas
[i
].content
;
510 if (allMetas
[i
].name
== 'controlVis') {
511 controlVis
= allMetas
[i
].content
;
516 // Key trap fix, new function body for trap()
523 modifierKey
= e
.ctrlKey
|| e
.altKey
|| e
.metaKey
;
528 return modifierKey
|| e
.which
== 0;
533 if (!isOp
) createControls();
540 incrementals
= createIncrementals();
542 if (defaultView
== 'outline') {
545 document
.onkeyup
= keys
;
546 document
.onkeypress
= trap
;
547 document
.onclick
= clicker
;
551 window
.onload
= startup
;
552 window
.onresize = function(){setTimeout('fontScale()', 50);}