Mercurial > hg > Members > kaito > slides
comparison trunk/.svn/text-base/slides.js.svn-base @ 0:845ff8ff4fc9
1st
author | Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 14 Jan 2014 01:31:42 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:845ff8ff4fc9 |
---|---|
1 /* | |
2 Google HTML5 slides template | |
3 | |
4 Authors: Luke Mahé (code) | |
5 Marcin Wichary (code and design) | |
6 | |
7 Dominic Mazzoni (browser compatibility) | |
8 Charles Chen (ChromeVox support) | |
9 | |
10 URL: http://code.google.com/p/html5slides/ | |
11 */ | |
12 | |
13 var PERMANENT_URL_PREFIX = 'http://html5slides.googlecode.com/svn/trunk/'; | |
14 | |
15 var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next']; | |
16 | |
17 var PM_TOUCH_SENSITIVITY = 15; | |
18 | |
19 var curSlide; | |
20 | |
21 /* ---------------------------------------------------------------------- */ | |
22 /* classList polyfill by Eli Grey | |
23 * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */ | |
24 | |
25 if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { | |
26 | |
27 (function (view) { | |
28 | |
29 var | |
30 classListProp = "classList" | |
31 , protoProp = "prototype" | |
32 , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] | |
33 , objCtr = Object | |
34 strTrim = String[protoProp].trim || function () { | |
35 return this.replace(/^\s+|\s+$/g, ""); | |
36 } | |
37 , arrIndexOf = Array[protoProp].indexOf || function (item) { | |
38 for (var i = 0, len = this.length; i < len; i++) { | |
39 if (i in this && this[i] === item) { | |
40 return i; | |
41 } | |
42 } | |
43 return -1; | |
44 } | |
45 // Vendors: please allow content code to instantiate DOMExceptions | |
46 , DOMEx = function (type, message) { | |
47 this.name = type; | |
48 this.code = DOMException[type]; | |
49 this.message = message; | |
50 } | |
51 , checkTokenAndGetIndex = function (classList, token) { | |
52 if (token === "") { | |
53 throw new DOMEx( | |
54 "SYNTAX_ERR" | |
55 , "An invalid or illegal string was specified" | |
56 ); | |
57 } | |
58 if (/\s/.test(token)) { | |
59 throw new DOMEx( | |
60 "INVALID_CHARACTER_ERR" | |
61 , "String contains an invalid character" | |
62 ); | |
63 } | |
64 return arrIndexOf.call(classList, token); | |
65 } | |
66 , ClassList = function (elem) { | |
67 var | |
68 trimmedClasses = strTrim.call(elem.className) | |
69 , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] | |
70 ; | |
71 for (var i = 0, len = classes.length; i < len; i++) { | |
72 this.push(classes[i]); | |
73 } | |
74 this._updateClassName = function () { | |
75 elem.className = this.toString(); | |
76 }; | |
77 } | |
78 , classListProto = ClassList[protoProp] = [] | |
79 , classListGetter = function () { | |
80 return new ClassList(this); | |
81 } | |
82 ; | |
83 // Most DOMException implementations don't allow calling DOMException's toString() | |
84 // on non-DOMExceptions. Error's toString() is sufficient here. | |
85 DOMEx[protoProp] = Error[protoProp]; | |
86 classListProto.item = function (i) { | |
87 return this[i] || null; | |
88 }; | |
89 classListProto.contains = function (token) { | |
90 token += ""; | |
91 return checkTokenAndGetIndex(this, token) !== -1; | |
92 }; | |
93 classListProto.add = function (token) { | |
94 token += ""; | |
95 if (checkTokenAndGetIndex(this, token) === -1) { | |
96 this.push(token); | |
97 this._updateClassName(); | |
98 } | |
99 }; | |
100 classListProto.remove = function (token) { | |
101 token += ""; | |
102 var index = checkTokenAndGetIndex(this, token); | |
103 if (index !== -1) { | |
104 this.splice(index, 1); | |
105 this._updateClassName(); | |
106 } | |
107 }; | |
108 classListProto.toggle = function (token) { | |
109 token += ""; | |
110 if (checkTokenAndGetIndex(this, token) === -1) { | |
111 this.add(token); | |
112 } else { | |
113 this.remove(token); | |
114 } | |
115 }; | |
116 classListProto.toString = function () { | |
117 return this.join(" "); | |
118 }; | |
119 | |
120 if (objCtr.defineProperty) { | |
121 var classListPropDesc = { | |
122 get: classListGetter | |
123 , enumerable: true | |
124 , configurable: true | |
125 }; | |
126 try { | |
127 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); | |
128 } catch (ex) { // IE 8 doesn't support enumerable:true | |
129 if (ex.number === -0x7FF5EC54) { | |
130 classListPropDesc.enumerable = false; | |
131 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); | |
132 } | |
133 } | |
134 } else if (objCtr[protoProp].__defineGetter__) { | |
135 elemCtrProto.__defineGetter__(classListProp, classListGetter); | |
136 } | |
137 | |
138 }(self)); | |
139 | |
140 } | |
141 /* ---------------------------------------------------------------------- */ | |
142 | |
143 /* Slide movement */ | |
144 | |
145 function getSlideEl(no) { | |
146 if ((no < 0) || (no >= slideEls.length)) { | |
147 return null; | |
148 } else { | |
149 return slideEls[no]; | |
150 } | |
151 }; | |
152 | |
153 function updateSlideClass(slideNo, className) { | |
154 var el = getSlideEl(slideNo); | |
155 | |
156 if (!el) { | |
157 return; | |
158 } | |
159 | |
160 if (className) { | |
161 el.classList.add(className); | |
162 } | |
163 | |
164 for (var i in SLIDE_CLASSES) { | |
165 if (className != SLIDE_CLASSES[i]) { | |
166 el.classList.remove(SLIDE_CLASSES[i]); | |
167 } | |
168 } | |
169 }; | |
170 | |
171 function updateSlides() { | |
172 for (var i = 0; i < slideEls.length; i++) { | |
173 switch (i) { | |
174 case curSlide - 2: | |
175 updateSlideClass(i, 'far-past'); | |
176 break; | |
177 case curSlide - 1: | |
178 updateSlideClass(i, 'past'); | |
179 break; | |
180 case curSlide: | |
181 updateSlideClass(i, 'current'); | |
182 break; | |
183 case curSlide + 1: | |
184 updateSlideClass(i, 'next'); | |
185 break; | |
186 case curSlide + 2: | |
187 updateSlideClass(i, 'far-next'); | |
188 break; | |
189 default: | |
190 updateSlideClass(i); | |
191 break; | |
192 } | |
193 } | |
194 | |
195 triggerLeaveEvent(curSlide - 1); | |
196 triggerEnterEvent(curSlide); | |
197 | |
198 window.setTimeout(function() { | |
199 // Hide after the slide | |
200 disableSlideFrames(curSlide - 2); | |
201 }, 301); | |
202 | |
203 enableSlideFrames(curSlide - 1); | |
204 enableSlideFrames(curSlide + 2); | |
205 | |
206 if (isChromeVoxActive()) { | |
207 speakAndSyncToNode(slideEls[curSlide]); | |
208 } | |
209 | |
210 updateHash(); | |
211 }; | |
212 | |
213 function buildNextItem() { | |
214 var toBuild = slideEls[curSlide].querySelectorAll('.to-build'); | |
215 | |
216 if (!toBuild.length) { | |
217 return false; | |
218 } | |
219 | |
220 toBuild[0].classList.remove('to-build', ''); | |
221 | |
222 if (isChromeVoxActive()) { | |
223 speakAndSyncToNode(toBuild[0]); | |
224 } | |
225 | |
226 return true; | |
227 }; | |
228 | |
229 function prevSlide() { | |
230 if (curSlide > 0) { | |
231 curSlide--; | |
232 | |
233 updateSlides(); | |
234 } | |
235 }; | |
236 | |
237 function nextSlide() { | |
238 if (buildNextItem()) { | |
239 return; | |
240 } | |
241 | |
242 if (curSlide < slideEls.length - 1) { | |
243 curSlide++; | |
244 | |
245 updateSlides(); | |
246 } | |
247 }; | |
248 | |
249 /* Slide events */ | |
250 | |
251 function triggerEnterEvent(no) { | |
252 var el = getSlideEl(no); | |
253 if (!el) { | |
254 return; | |
255 } | |
256 | |
257 var onEnter = el.getAttribute('onslideenter'); | |
258 if (onEnter) { | |
259 new Function(onEnter).call(el); | |
260 } | |
261 | |
262 var evt = document.createEvent('Event'); | |
263 evt.initEvent('slideenter', true, true); | |
264 evt.slideNumber = no + 1; // Make it readable | |
265 | |
266 el.dispatchEvent(evt); | |
267 }; | |
268 | |
269 function triggerLeaveEvent(no) { | |
270 var el = getSlideEl(no); | |
271 if (!el) { | |
272 return; | |
273 } | |
274 | |
275 var onLeave = el.getAttribute('onslideleave'); | |
276 if (onLeave) { | |
277 new Function(onLeave).call(el); | |
278 } | |
279 | |
280 var evt = document.createEvent('Event'); | |
281 evt.initEvent('slideleave', true, true); | |
282 evt.slideNumber = no + 1; // Make it readable | |
283 | |
284 el.dispatchEvent(evt); | |
285 }; | |
286 | |
287 /* Touch events */ | |
288 | |
289 function handleTouchStart(event) { | |
290 if (event.touches.length == 1) { | |
291 touchDX = 0; | |
292 touchDY = 0; | |
293 | |
294 touchStartX = event.touches[0].pageX; | |
295 touchStartY = event.touches[0].pageY; | |
296 | |
297 document.body.addEventListener('touchmove', handleTouchMove, true); | |
298 document.body.addEventListener('touchend', handleTouchEnd, true); | |
299 } | |
300 }; | |
301 | |
302 function handleTouchMove(event) { | |
303 if (event.touches.length > 1) { | |
304 cancelTouch(); | |
305 } else { | |
306 touchDX = event.touches[0].pageX - touchStartX; | |
307 touchDY = event.touches[0].pageY - touchStartY; | |
308 } | |
309 }; | |
310 | |
311 function handleTouchEnd(event) { | |
312 var dx = Math.abs(touchDX); | |
313 var dy = Math.abs(touchDY); | |
314 | |
315 if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) { | |
316 if (touchDX > 0) { | |
317 prevSlide(); | |
318 } else { | |
319 nextSlide(); | |
320 } | |
321 } | |
322 | |
323 cancelTouch(); | |
324 }; | |
325 | |
326 function cancelTouch() { | |
327 document.body.removeEventListener('touchmove', handleTouchMove, true); | |
328 document.body.removeEventListener('touchend', handleTouchEnd, true); | |
329 }; | |
330 | |
331 /* Preloading frames */ | |
332 | |
333 function disableSlideFrames(no) { | |
334 var el = getSlideEl(no); | |
335 if (!el) { | |
336 return; | |
337 } | |
338 | |
339 var frames = el.getElementsByTagName('iframe'); | |
340 for (var i = 0, frame; frame = frames[i]; i++) { | |
341 disableFrame(frame); | |
342 } | |
343 }; | |
344 | |
345 function enableSlideFrames(no) { | |
346 var el = getSlideEl(no); | |
347 if (!el) { | |
348 return; | |
349 } | |
350 | |
351 var frames = el.getElementsByTagName('iframe'); | |
352 for (var i = 0, frame; frame = frames[i]; i++) { | |
353 enableFrame(frame); | |
354 } | |
355 }; | |
356 | |
357 function disableFrame(frame) { | |
358 frame.src = 'about:blank'; | |
359 }; | |
360 | |
361 function enableFrame(frame) { | |
362 var src = frame._src; | |
363 | |
364 if (frame.src != src && src != 'about:blank') { | |
365 frame.src = src; | |
366 } | |
367 }; | |
368 | |
369 function setupFrames() { | |
370 var frames = document.querySelectorAll('iframe'); | |
371 for (var i = 0, frame; frame = frames[i]; i++) { | |
372 frame._src = frame.src; | |
373 disableFrame(frame); | |
374 } | |
375 | |
376 enableSlideFrames(curSlide); | |
377 enableSlideFrames(curSlide + 1); | |
378 enableSlideFrames(curSlide + 2); | |
379 }; | |
380 | |
381 function setupInteraction() { | |
382 /* Clicking and tapping */ | |
383 | |
384 var el = document.createElement('div'); | |
385 el.className = 'slide-area'; | |
386 el.id = 'prev-slide-area'; | |
387 el.addEventListener('click', prevSlide, false); | |
388 document.querySelector('section.slides').appendChild(el); | |
389 | |
390 var el = document.createElement('div'); | |
391 el.className = 'slide-area'; | |
392 el.id = 'next-slide-area'; | |
393 el.addEventListener('click', nextSlide, false); | |
394 document.querySelector('section.slides').appendChild(el); | |
395 | |
396 /* Swiping */ | |
397 | |
398 document.body.addEventListener('touchstart', handleTouchStart, false); | |
399 } | |
400 | |
401 /* ChromeVox support */ | |
402 | |
403 function isChromeVoxActive() { | |
404 if (typeof(cvox) == 'undefined') { | |
405 return false; | |
406 } else { | |
407 return true; | |
408 } | |
409 }; | |
410 | |
411 function speakAndSyncToNode(node) { | |
412 if (!isChromeVoxActive()) { | |
413 return; | |
414 } | |
415 | |
416 cvox.ChromeVox.navigationManager.switchToStrategy( | |
417 cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
418 cvox.ChromeVox.navigationManager.syncToNode(node); | |
419 cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
420 var target = node; | |
421 while (target.firstChild) { | |
422 target = target.firstChild; | |
423 } | |
424 cvox.ChromeVox.navigationManager.syncToNode(target); | |
425 }; | |
426 | |
427 function speakNextItem() { | |
428 if (!isChromeVoxActive()) { | |
429 return; | |
430 } | |
431 | |
432 cvox.ChromeVox.navigationManager.switchToStrategy( | |
433 cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
434 cvox.ChromeVox.navigationManager.next(true); | |
435 if (!cvox.DomUtil.isDescendantOfNode( | |
436 cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ | |
437 var target = slideEls[curSlide]; | |
438 while (target.firstChild) { | |
439 target = target.firstChild; | |
440 } | |
441 cvox.ChromeVox.navigationManager.syncToNode(target); | |
442 cvox.ChromeVox.navigationManager.next(true); | |
443 } | |
444 cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
445 }; | |
446 | |
447 function speakPrevItem() { | |
448 if (!isChromeVoxActive()) { | |
449 return; | |
450 } | |
451 | |
452 cvox.ChromeVox.navigationManager.switchToStrategy( | |
453 cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
454 cvox.ChromeVox.navigationManager.previous(true); | |
455 if (!cvox.DomUtil.isDescendantOfNode( | |
456 cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ | |
457 var target = slideEls[curSlide]; | |
458 while (target.lastChild){ | |
459 target = target.lastChild; | |
460 } | |
461 cvox.ChromeVox.navigationManager.syncToNode(target); | |
462 cvox.ChromeVox.navigationManager.previous(true); | |
463 } | |
464 cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
465 }; | |
466 | |
467 /* Hash functions */ | |
468 | |
469 function getCurSlideFromHash() { | |
470 var slideNo = parseInt(location.hash.substr(1)); | |
471 | |
472 if (slideNo) { | |
473 curSlide = slideNo - 1; | |
474 } else { | |
475 curSlide = 0; | |
476 } | |
477 }; | |
478 | |
479 function updateHash() { | |
480 location.replace('#' + (curSlide + 1)); | |
481 }; | |
482 | |
483 /* Event listeners */ | |
484 | |
485 function handleBodyKeyDown(event) { | |
486 switch (event.keyCode) { | |
487 case 39: // right arrow | |
488 case 13: // Enter | |
489 case 32: // space | |
490 case 34: // PgDn | |
491 nextSlide(); | |
492 event.preventDefault(); | |
493 break; | |
494 | |
495 case 37: // left arrow | |
496 case 8: // Backspace | |
497 case 33: // PgUp | |
498 prevSlide(); | |
499 event.preventDefault(); | |
500 break; | |
501 | |
502 case 40: // down arrow | |
503 if (isChromeVoxActive()) { | |
504 speakNextItem(); | |
505 } else { | |
506 nextSlide(); | |
507 } | |
508 event.preventDefault(); | |
509 break; | |
510 | |
511 case 38: // up arrow | |
512 if (isChromeVoxActive()) { | |
513 speakPrevItem(); | |
514 } else { | |
515 prevSlide(); | |
516 } | |
517 event.preventDefault(); | |
518 break; | |
519 } | |
520 }; | |
521 | |
522 function addEventListeners() { | |
523 document.addEventListener('keydown', handleBodyKeyDown, false); | |
524 }; | |
525 | |
526 /* Initialization */ | |
527 | |
528 function addPrettify() { | |
529 var els = document.querySelectorAll('pre'); | |
530 for (var i = 0, el; el = els[i]; i++) { | |
531 if (!el.classList.contains('noprettyprint')) { | |
532 el.classList.add('prettyprint'); | |
533 } | |
534 } | |
535 | |
536 var el = document.createElement('script'); | |
537 el.type = 'text/javascript'; | |
538 el.src = PERMANENT_URL_PREFIX + 'prettify.js'; | |
539 el.onload = function() { | |
540 prettyPrint(); | |
541 } | |
542 document.body.appendChild(el); | |
543 }; | |
544 | |
545 function addFontStyle() { | |
546 var el = document.createElement('link'); | |
547 el.rel = 'stylesheet'; | |
548 el.type = 'text/css'; | |
549 el.href = 'http://fonts.googleapis.com/css?family=' + | |
550 'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono'; | |
551 | |
552 document.body.appendChild(el); | |
553 }; | |
554 | |
555 function addGeneralStyle() { | |
556 var el = document.createElement('link'); | |
557 el.rel = 'stylesheet'; | |
558 el.type = 'text/css'; | |
559 el.href = PERMANENT_URL_PREFIX + 'styles.css'; | |
560 document.body.appendChild(el); | |
561 | |
562 var el = document.createElement('meta'); | |
563 el.name = 'viewport'; | |
564 el.content = 'width=1100,height=750'; | |
565 document.querySelector('head').appendChild(el); | |
566 | |
567 var el = document.createElement('meta'); | |
568 el.name = 'apple-mobile-web-app-capable'; | |
569 el.content = 'yes'; | |
570 document.querySelector('head').appendChild(el); | |
571 }; | |
572 | |
573 function makeBuildLists() { | |
574 for (var i = curSlide, slide; slide = slideEls[i]; i++) { | |
575 var items = slide.querySelectorAll('.build > *'); | |
576 for (var j = 0, item; item = items[j]; j++) { | |
577 if (item.classList) { | |
578 item.classList.add('to-build'); | |
579 } | |
580 } | |
581 } | |
582 }; | |
583 | |
584 function handleDomLoaded() { | |
585 slideEls = document.querySelectorAll('section.slides > article'); | |
586 | |
587 setupFrames(); | |
588 | |
589 addFontStyle(); | |
590 addGeneralStyle(); | |
591 addPrettify(); | |
592 addEventListeners(); | |
593 | |
594 updateSlides(); | |
595 | |
596 setupInteraction(); | |
597 makeBuildLists(); | |
598 | |
599 document.body.classList.add('loaded'); | |
600 }; | |
601 | |
602 function initialize() { | |
603 getCurSlideFromHash(); | |
604 | |
605 if (window['_DEBUG']) { | |
606 PERMANENT_URL_PREFIX = '../'; | |
607 } | |
608 | |
609 if (window['_DCL']) { | |
610 handleDomLoaded(); | |
611 } else { | |
612 document.addEventListener('DOMContentLoaded', handleDomLoaded, false); | |
613 } | |
614 } | |
615 | |
616 // If ?debug exists then load the script relative instead of absolute | |
617 if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) { | |
618 document.addEventListener('DOMContentLoaded', function() { | |
619 // Avoid missing the DomContentLoaded event | |
620 window['_DCL'] = true | |
621 }, false); | |
622 | |
623 window['_DEBUG'] = true; | |
624 var script = document.createElement('script'); | |
625 script.type = 'text/javascript'; | |
626 script.src = '../slides.js'; | |
627 var s = document.getElementsByTagName('script')[0]; | |
628 s.parentNode.insertBefore(script, s); | |
629 | |
630 // Remove this script | |
631 s.parentNode.removeChild(s); | |
632 } else { | |
633 initialize(); | |
634 } |