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 }