Last active
December 14, 2015 06:28
-
-
Save rbreve/5042323 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Google HTML5 slides template | |
Authors: Luke Mahé (code) | |
Marcin Wichary (code and design) | |
Dominic Mazzoni (browser compatibility) | |
Charles Chen (ChromeVox support) | |
URL: http://code.google.com/p/html5slides/ | |
*/ | |
var PERMANENT_URL_PREFIX = 'http://html5slides.googlecode.com/svn/trunk/'; | |
var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next']; | |
var PM_TOUCH_SENSITIVITY = 15; | |
var curSlide; | |
/* ---------------------------------------------------------------------- */ | |
/* classList polyfill by Eli Grey | |
* (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */ | |
if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { | |
(function (view) { | |
var | |
classListProp = "classList" | |
, protoProp = "prototype" | |
, elemCtrProto = (view.HTMLElement || view.Element)[protoProp] | |
, objCtr = Object | |
strTrim = String[protoProp].trim || function () { | |
return this.replace(/^\s+|\s+$/g, ""); | |
} | |
, arrIndexOf = Array[protoProp].indexOf || function (item) { | |
for (var i = 0, len = this.length; i < len; i++) { | |
if (i in this && this[i] === item) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
// Vendors: please allow content code to instantiate DOMExceptions | |
, DOMEx = function (type, message) { | |
this.name = type; | |
this.code = DOMException[type]; | |
this.message = message; | |
} | |
, checkTokenAndGetIndex = function (classList, token) { | |
if (token === "") { | |
throw new DOMEx( | |
"SYNTAX_ERR" | |
, "An invalid or illegal string was specified" | |
); | |
} | |
if (/\s/.test(token)) { | |
throw new DOMEx( | |
"INVALID_CHARACTER_ERR" | |
, "String contains an invalid character" | |
); | |
} | |
return arrIndexOf.call(classList, token); | |
} | |
, ClassList = function (elem) { | |
var | |
trimmedClasses = strTrim.call(elem.className) | |
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] | |
; | |
for (var i = 0, len = classes.length; i < len; i++) { | |
this.push(classes[i]); | |
} | |
this._updateClassName = function () { | |
elem.className = this.toString(); | |
}; | |
} | |
, classListProto = ClassList[protoProp] = [] | |
, classListGetter = function () { | |
return new ClassList(this); | |
} | |
; | |
// Most DOMException implementations don't allow calling DOMException's toString() | |
// on non-DOMExceptions. Error's toString() is sufficient here. | |
DOMEx[protoProp] = Error[protoProp]; | |
classListProto.item = function (i) { | |
return this[i] || null; | |
}; | |
classListProto.contains = function (token) { | |
token += ""; | |
return checkTokenAndGetIndex(this, token) !== -1; | |
}; | |
classListProto.add = function (token) { | |
token += ""; | |
if (checkTokenAndGetIndex(this, token) === -1) { | |
this.push(token); | |
this._updateClassName(); | |
} | |
}; | |
classListProto.remove = function (token) { | |
token += ""; | |
var index = checkTokenAndGetIndex(this, token); | |
if (index !== -1) { | |
this.splice(index, 1); | |
this._updateClassName(); | |
} | |
}; | |
classListProto.toggle = function (token) { | |
token += ""; | |
if (checkTokenAndGetIndex(this, token) === -1) { | |
this.add(token); | |
} else { | |
this.remove(token); | |
} | |
}; | |
classListProto.toString = function () { | |
return this.join(" "); | |
}; | |
if (objCtr.defineProperty) { | |
var classListPropDesc = { | |
get: classListGetter | |
, enumerable: true | |
, configurable: true | |
}; | |
try { | |
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); | |
} catch (ex) { // IE 8 doesn't support enumerable:true | |
if (ex.number === -0x7FF5EC54) { | |
classListPropDesc.enumerable = false; | |
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); | |
} | |
} | |
} else if (objCtr[protoProp].__defineGetter__) { | |
elemCtrProto.__defineGetter__(classListProp, classListGetter); | |
} | |
}(self)); | |
} | |
/* ---------------------------------------------------------------------- */ | |
/* Slide movement */ | |
function getSlideEl(no) { | |
if ((no < 0) || (no >= slideEls.length)) { | |
return null; | |
} else { | |
return slideEls[no]; | |
} | |
}; | |
function updateSlideClass(slideNo, className) { | |
var el = getSlideEl(slideNo); | |
if (!el) { | |
return; | |
} | |
if (className) { | |
el.classList.add(className); | |
} | |
for (var i in SLIDE_CLASSES) { | |
if (className != SLIDE_CLASSES[i]) { | |
el.classList.remove(SLIDE_CLASSES[i]); | |
} | |
} | |
}; | |
function updateSlides() { | |
for (var i = 0; i < slideEls.length; i++) { | |
switch (i) { | |
case curSlide - 2: | |
updateSlideClass(i, 'far-past'); | |
break; | |
case curSlide - 1: | |
updateSlideClass(i, 'past'); | |
break; | |
case curSlide: | |
updateSlideClass(i, 'current'); | |
break; | |
case curSlide + 1: | |
updateSlideClass(i, 'next'); | |
break; | |
case curSlide + 2: | |
updateSlideClass(i, 'far-next'); | |
break; | |
default: | |
updateSlideClass(i); | |
break; | |
} | |
} | |
triggerLeaveEvent(curSlide - 1); | |
triggerEnterEvent(curSlide); | |
window.setTimeout(function() { | |
// Hide after the slide | |
disableSlideFrames(curSlide - 2); | |
}, 301); | |
enableSlideFrames(curSlide - 1); | |
enableSlideFrames(curSlide + 2); | |
if (isChromeVoxActive()) { | |
speakAndSyncToNode(slideEls[curSlide]); | |
} | |
updateHash(); | |
}; | |
function buildNextItem() { | |
var toBuild = slideEls[curSlide].querySelectorAll('.to-build'); | |
if (!toBuild.length) { | |
return false; | |
} | |
toBuild[0].classList.remove('to-build'); | |
if (isChromeVoxActive()) { | |
speakAndSyncToNode(toBuild[0]); | |
} | |
return true; | |
}; | |
function prevSlide() { | |
if (curSlide > 0) { | |
curSlide--; | |
updateSlides(); | |
} | |
}; | |
function nextSlide() { | |
if (buildNextItem()) { | |
return; | |
} | |
if (curSlide < slideEls.length - 1) { | |
curSlide++; | |
updateSlides(); | |
} | |
}; | |
/* Slide events */ | |
function triggerEnterEvent(no) { | |
var el = getSlideEl(no); | |
if (!el) { | |
return; | |
} | |
var onEnter = el.getAttribute('onslideenter'); | |
if (onEnter) { | |
new Function(onEnter).call(el); | |
} | |
var evt = document.createEvent('Event'); | |
evt.initEvent('slideenter', true, true); | |
evt.slideNumber = no + 1; // Make it readable | |
el.dispatchEvent(evt); | |
}; | |
function triggerLeaveEvent(no) { | |
var el = getSlideEl(no); | |
if (!el) { | |
return; | |
} | |
var onLeave = el.getAttribute('onslideleave'); | |
if (onLeave) { | |
new Function(onLeave).call(el); | |
} | |
var evt = document.createEvent('Event'); | |
evt.initEvent('slideleave', true, true); | |
evt.slideNumber = no + 1; // Make it readable | |
el.dispatchEvent(evt); | |
}; | |
/* Touch events */ | |
function handleTouchStart(event) { | |
if (event.touches.length == 1) { | |
touchDX = 0; | |
touchDY = 0; | |
touchStartX = event.touches[0].pageX; | |
touchStartY = event.touches[0].pageY; | |
document.body.addEventListener('touchmove', handleTouchMove, true); | |
document.body.addEventListener('touchend', handleTouchEnd, true); | |
} | |
}; | |
function handleTouchMove(event) { | |
if (event.touches.length > 1) { | |
cancelTouch(); | |
} else { | |
touchDX = event.touches[0].pageX - touchStartX; | |
touchDY = event.touches[0].pageY - touchStartY; | |
} | |
}; | |
function handleTouchEnd(event) { | |
var dx = Math.abs(touchDX); | |
var dy = Math.abs(touchDY); | |
if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) { | |
if (touchDX > 0) { | |
prevSlide(); | |
} else { | |
nextSlide(); | |
} | |
} | |
cancelTouch(); | |
}; | |
function cancelTouch() { | |
document.body.removeEventListener('touchmove', handleTouchMove, true); | |
document.body.removeEventListener('touchend', handleTouchEnd, true); | |
}; | |
/* Preloading frames */ | |
function disableSlideFrames(no) { | |
var el = getSlideEl(no); | |
if (!el) { | |
return; | |
} | |
var frames = el.getElementsByTagName('iframe'); | |
for (var i = 0, frame; frame = frames[i]; i++) { | |
disableFrame(frame); | |
} | |
}; | |
function enableSlideFrames(no) { | |
var el = getSlideEl(no); | |
if (!el) { | |
return; | |
} | |
var frames = el.getElementsByTagName('iframe'); | |
for (var i = 0, frame; frame = frames[i]; i++) { | |
enableFrame(frame); | |
} | |
}; | |
function disableFrame(frame) { | |
frame.src = 'about:blank'; | |
}; | |
function enableFrame(frame) { | |
var src = frame._src; | |
if (frame.src != src && src != 'about:blank') { | |
frame.src = src; | |
} | |
}; | |
function setupFrames() { | |
var frames = document.querySelectorAll('iframe'); | |
for (var i = 0, frame; frame = frames[i]; i++) { | |
frame._src = frame.src; | |
disableFrame(frame); | |
} | |
enableSlideFrames(curSlide); | |
enableSlideFrames(curSlide + 1); | |
enableSlideFrames(curSlide + 2); | |
}; | |
function setupInteraction() { | |
/* Clicking and tapping */ | |
var el = document.createElement('div'); | |
el.className = 'slide-area'; | |
el.id = 'prev-slide-area'; | |
el.addEventListener('click', prevSlide, false); | |
document.querySelector('section.slides').appendChild(el); | |
var el = document.createElement('div'); | |
el.className = 'slide-area'; | |
el.id = 'next-slide-area'; | |
el.addEventListener('click', nextSlide, false); | |
document.querySelector('section.slides').appendChild(el); | |
/* Swiping */ | |
document.body.addEventListener('touchstart', handleTouchStart, false); | |
} | |
/* ChromeVox support */ | |
function isChromeVoxActive() { | |
if (typeof(cvox) == 'undefined') { | |
return false; | |
} else { | |
return true; | |
} | |
}; | |
function speakAndSyncToNode(node) { | |
if (!isChromeVoxActive()) { | |
return; | |
} | |
cvox.ChromeVox.navigationManager.switchToStrategy( | |
cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
cvox.ChromeVox.navigationManager.syncToNode(node); | |
cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
var target = node; | |
while (target.firstChild) { | |
target = target.firstChild; | |
} | |
cvox.ChromeVox.navigationManager.syncToNode(target); | |
}; | |
function speakNextItem() { | |
if (!isChromeVoxActive()) { | |
return; | |
} | |
cvox.ChromeVox.navigationManager.switchToStrategy( | |
cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
cvox.ChromeVox.navigationManager.next(true); | |
if (!cvox.DomUtil.isDescendantOfNode( | |
cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ | |
var target = slideEls[curSlide]; | |
while (target.firstChild) { | |
target = target.firstChild; | |
} | |
cvox.ChromeVox.navigationManager.syncToNode(target); | |
cvox.ChromeVox.navigationManager.next(true); | |
} | |
cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
}; | |
function speakPrevItem() { | |
if (!isChromeVoxActive()) { | |
return; | |
} | |
cvox.ChromeVox.navigationManager.switchToStrategy( | |
cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); | |
cvox.ChromeVox.navigationManager.previous(true); | |
if (!cvox.DomUtil.isDescendantOfNode( | |
cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ | |
var target = slideEls[curSlide]; | |
while (target.lastChild){ | |
target = target.lastChild; | |
} | |
cvox.ChromeVox.navigationManager.syncToNode(target); | |
cvox.ChromeVox.navigationManager.previous(true); | |
} | |
cvox.ChromeVoxUserCommands.finishNavCommand(''); | |
}; | |
/* Hash functions */ | |
function getCurSlideFromHash() { | |
var slideNo = parseInt(location.hash.substr(1)); | |
if (slideNo) { | |
curSlide = slideNo - 1; | |
} else { | |
curSlide = 0; | |
} | |
}; | |
function updateHash() { | |
location.replace('#' + (curSlide + 1)); | |
}; | |
/* Event listeners */ | |
function handleBodyKeyDown(event) { | |
switch (event.keyCode) { | |
case 39: // right arrow | |
case 13: // Enter | |
case 32: // space | |
case 34: // PgDn | |
nextSlide(); | |
event.preventDefault(); | |
break; | |
case 37: // left arrow | |
case 8: // Backspace | |
case 33: // PgUp | |
prevSlide(); | |
event.preventDefault(); | |
break; | |
case 40: // down arrow | |
if (isChromeVoxActive()) { | |
speakNextItem(); | |
} else { | |
nextSlide(); | |
} | |
event.preventDefault(); | |
break; | |
case 38: // up arrow | |
if (isChromeVoxActive()) { | |
speakPrevItem(); | |
} else { | |
prevSlide(); | |
} | |
event.preventDefault(); | |
break; | |
} | |
}; | |
function addEventListeners() { | |
document.addEventListener('keydown', handleBodyKeyDown, false); | |
}; | |
/* Initialization */ | |
function addPrettify() { | |
var els = document.querySelectorAll('pre'); | |
for (var i = 0, el; el = els[i]; i++) { | |
if (!el.classList.contains('noprettyprint')) { | |
el.classList.add('prettyprint'); | |
} | |
} | |
var el = document.createElement('script'); | |
el.type = 'text/javascript'; | |
el.src = PERMANENT_URL_PREFIX + 'prettify.js'; | |
el.onload = function() { | |
prettyPrint(); | |
} | |
document.body.appendChild(el); | |
}; | |
function addFontStyle() { | |
var el = document.createElement('link'); | |
el.rel = 'stylesheet'; | |
el.type = 'text/css'; | |
el.href = 'http://fonts.googleapis.com/css?family=' + | |
'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono'; | |
document.body.appendChild(el); | |
}; | |
function addGeneralStyle() { | |
var el = document.createElement('link'); | |
el.rel = 'stylesheet'; | |
el.type = 'text/css'; | |
el.href = PERMANENT_URL_PREFIX + 'styles.css'; | |
document.body.appendChild(el); | |
var el = document.createElement('meta'); | |
el.name = 'viewport'; | |
el.content = 'width=1100,height=750'; | |
document.querySelector('head').appendChild(el); | |
var el = document.createElement('meta'); | |
el.name = 'apple-mobile-web-app-capable'; | |
el.content = 'yes'; | |
document.querySelector('head').appendChild(el); | |
}; | |
function makeBuildLists() { | |
for (var i = curSlide, slide; slide = slideEls[i]; i++) { | |
var items = slide.querySelectorAll('.build > *'); | |
for (var j = 0, item; item = items[j]; j++) { | |
if (item.classList) { | |
item.classList.add('to-build'); | |
} | |
} | |
} | |
}; | |
function handleDomLoaded() { | |
slideEls = document.querySelectorAll('section.slides > article'); | |
setupFrames(); | |
addFontStyle(); | |
addGeneralStyle(); | |
addPrettify(); | |
addEventListeners(); | |
updateSlides(); | |
setupInteraction(); | |
makeBuildLists(); | |
document.body.classList.add('loaded'); | |
}; | |
function initialize() { | |
getCurSlideFromHash(); | |
if (window['_DEBUG']) { | |
PERMANENT_URL_PREFIX = '../'; | |
} | |
if (window['_DCL']) { | |
handleDomLoaded(); | |
} else { | |
document.addEventListener('DOMContentLoaded', handleDomLoaded, false); | |
} | |
} | |
// If ?debug exists then load the script relative instead of absolute | |
if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) { | |
document.addEventListener('DOMContentLoaded', function() { | |
// Avoid missing the DomContentLoaded event | |
window['_DCL'] = true | |
}, false); | |
window['_DEBUG'] = true; | |
var script = document.createElement('script'); | |
script.type = 'text/javascript'; | |
script.src = '../slides.js'; | |
var s = document.getElementsByTagName('script')[0]; | |
s.parentNode.insertBefore(script, s); | |
// Remove this script | |
s.parentNode.removeChild(s); | |
} else { | |
initialize(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment