From 765d63c299db8b75217b578b3a295fbce5d7abd3 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Mon, 12 May 2014 21:40:42 +0200 Subject: Import and format code --- js/slide-controller.js | 213 ++++----- js/slide-deck.js | 1229 +++++++++++++++++++++++++----------------------- js/slides.js | 6 +- 3 files changed, 746 insertions(+), 702 deletions(-) (limited to 'js') diff --git a/js/slide-controller.js b/js/slide-controller.js index 571317b..9dcb4df 100644 --- a/js/slide-controller.js +++ b/js/slide-controller.js @@ -1,109 +1,112 @@ (function(window) { -var ORIGIN_ = location.protocol + '//' + location.host; - -function SlideController() { - this.popup = null; - this.isPopup = window.opener; - - if (this.setupDone()) { - window.addEventListener('message', this.onMessage_.bind(this), false); - - // Close popups if we reload the main window. - window.addEventListener('beforeunload', function(e) { - if (this.popup) { - this.popup.close(); - } - }.bind(this), false); - } -} - -SlideController.PRESENTER_MODE_PARAM = 'presentme'; - -SlideController.prototype.setupDone = function() { - var params = location.search.substring(1).split('&').map(function(el) { - return el.split('='); - }); - - var presentMe = null; - for (var i = 0, param; param = params[i]; ++i) { - if (param[0].toLowerCase() == SlideController.PRESENTER_MODE_PARAM) { - presentMe = param[1] == 'true'; - break; - } - } - - if (presentMe !== null) { - localStorage.ENABLE_PRESENTOR_MODE = presentMe; - // TODO: use window.history.pushState to update URL instead of the redirect. - if (window.history.replaceState) { - window.history.replaceState({}, '', location.pathname); - } else { - location.replace(location.pathname); - return false; - } - } - - var enablePresenterMode = localStorage.getItem('ENABLE_PRESENTOR_MODE'); - if (enablePresenterMode && JSON.parse(enablePresenterMode)) { - // Only open popup from main deck. Don't want recursive popup opening! - if (!this.isPopup) { - var opts = 'menubar=no,location=yes,resizable=yes,scrollbars=no,status=no'; - this.popup = window.open(location.href, 'mywindow', opts); - - // Loading in the popup? Trigger the hotkey for turning presenter mode on. - this.popup.addEventListener('load', function(e) { - var evt = this.popup.document.createEvent('Event'); - evt.initEvent('keydown', true, true); - evt.keyCode = 'P'.charCodeAt(0); - this.popup.document.dispatchEvent(evt); - // this.popup.document.body.classList.add('with-notes'); - // document.body.classList.add('popup'); - }.bind(this), false); - } - } - - return true; -} - -SlideController.prototype.onMessage_ = function(e) { - var data = e.data; - - // Restrict messages to being from this origin. Allow local developmet - // from file:// though. - // TODO: It would be dope if FF implemented location.origin! - if (e.origin != ORIGIN_ && ORIGIN_.indexOf('file://') != 0) { - alert('Someone tried to postMessage from an unknown origin'); - return; - } - - // if (e.source.location.hostname != 'localhost') { - // alert('Someone tried to postMessage from an unknown origin'); - // return; - // } - - if ('keyCode' in data) { - var evt = document.createEvent('Event'); - evt.initEvent('keydown', true, true); - evt.keyCode = data.keyCode; - document.dispatchEvent(evt); - } -}; - -SlideController.prototype.sendMsg = function(msg) { - // // Send message to popup window. - // if (this.popup) { - // this.popup.postMessage(msg, ORIGIN_); - // } - - // Send message to main window. - if (this.isPopup) { - // TODO: It would be dope if FF implemented location.origin. - window.opener.postMessage(msg, '*'); - } -}; - -window.SlideController = SlideController; + var ORIGIN_ = location.protocol + '//' + location.host; + + function SlideController() { + this.popup = null; + this.isPopup = window.opener; + + if (this.setupDone()) { + window.addEventListener('message', this.onMessage_.bind(this), + false); + + // Close popups if we reload the main window. + window.addEventListener('beforeunload', function(e) { + if (this.popup) { + this.popup.close(); + } + }.bind(this), false); + } + } + + SlideController.PRESENTER_MODE_PARAM = 'presentme'; + + SlideController.prototype.setupDone = function() { + var params = location.search.substring(1).split('&').map(function(el) { + return el.split('='); + }); + + var presentMe = null; + for (var i = 0, param; param = params[i]; ++i) { + if (param[0].toLowerCase() == SlideController.PRESENTER_MODE_PARAM) { + presentMe = param[1] == 'true'; + break; + } + } + + if (presentMe !== null) { + localStorage.ENABLE_PRESENTOR_MODE = presentMe; + // TODO: use window.history.pushState to update URL instead of the + // redirect. + if (window.history.replaceState) { + window.history.replaceState({}, '', location.pathname); + } else { + location.replace(location.pathname); + return false; + } + } + + var enablePresenterMode = localStorage.getItem('ENABLE_PRESENTOR_MODE'); + if (enablePresenterMode && JSON.parse(enablePresenterMode)) { + // Only open popup from main deck. Don't want recursive popup + // opening! + if (!this.isPopup) { + var opts = 'menubar=no,location=yes,resizable=yes,scrollbars=no,status=no'; + this.popup = window.open(location.href, 'mywindow', opts); + + // Loading in the popup? Trigger the hotkey for turning + // presenter mode on. + this.popup.addEventListener('load', function(e) { + var evt = this.popup.document.createEvent('Event'); + evt.initEvent('keydown', true, true); + evt.keyCode = 'P'.charCodeAt(0); + this.popup.document.dispatchEvent(evt); + // this.popup.document.body.classList.add('with-notes'); + // document.body.classList.add('popup'); + }.bind(this), false); + } + } + + return true; + } + + SlideController.prototype.onMessage_ = function(e) { + var data = e.data; + + // Restrict messages to being from this origin. Allow local developmet + // from file:// though. + // TODO: It would be dope if FF implemented location.origin! + if (e.origin != ORIGIN_ && ORIGIN_.indexOf('file://') != 0) { + alert('Someone tried to postMessage from an unknown origin'); + return; + } + + // if (e.source.location.hostname != 'localhost') { + // alert('Someone tried to postMessage from an unknown origin'); + // return; + // } + + if ('keyCode' in data) { + var evt = document.createEvent('Event'); + evt.initEvent('keydown', true, true); + evt.keyCode = data.keyCode; + document.dispatchEvent(evt); + } + }; + + SlideController.prototype.sendMsg = function(msg) { + // // Send message to popup window. + // if (this.popup) { + // this.popup.postMessage(msg, ORIGIN_); + // } + + // Send message to main window. + if (this.isPopup) { + // TODO: It would be dope if FF implemented location.origin. + window.opener.postMessage(msg, '*'); + } + }; + + window.SlideController = SlideController; })(window); - diff --git a/js/slide-deck.js b/js/slide-deck.js index d792ddd..67aa4f2 100644 --- a/js/slide-deck.js +++ b/js/slide-deck.js @@ -3,32 +3,32 @@ * @authors Eric Bidelman * @fileoverview TODO */ -document.cancelFullScreen = document.webkitCancelFullScreen || - document.mozCancelFullScreen; +document.cancelFullScreen = document.webkitCancelFullScreen + || document.mozCancelFullScreen; /** * @constructor */ function SlideDeck(el) { - this.curSlide_ = 0; - this.prevSlide_ = 0; - this.config_ = null; - this.container = el || document.querySelector('slides'); - this.slides = []; - this.controller = null; + this.curSlide_ = 0; + this.prevSlide_ = 0; + this.config_ = null; + this.container = el || document.querySelector('slides'); + this.slides = []; + this.controller = null; - this.getCurrentSlideFromHash_(); + this.getCurrentSlideFromHash_(); - // Call this explicitly. Modernizr.load won't be done until after DOM load. - this.onDomLoaded_.bind(this)(); + // Call this explicitly. Modernizr.load won't be done until after DOM load. + this.onDomLoaded_.bind(this)(); } /** * @const * @private */ -SlideDeck.prototype.SLIDE_CLASSES_ = [ - 'far-past', 'past', 'current', 'next', 'far-next']; +SlideDeck.prototype.SLIDE_CLASSES_ = [ 'far-past', 'past', 'current', 'next', + 'far-next' ]; /** * @const @@ -40,744 +40,785 @@ SlideDeck.prototype.CSS_DIR_ = 'theme/css/'; * @private */ SlideDeck.prototype.getCurrentSlideFromHash_ = function() { - var slideNo = parseInt(document.location.hash.substr(1)); + var slideNo = parseInt(document.location.hash.substr(1)); - if (slideNo) { - this.curSlide_ = slideNo - 1; - } else { - this.curSlide_ = 0; - } + if (slideNo) { + this.curSlide_ = slideNo - 1; + } else { + this.curSlide_ = 0; + } }; /** - * @param {number} slideNo + * @param {number} + * slideNo */ SlideDeck.prototype.loadSlide = function(slideNo) { - if (slideNo) { - this.curSlide_ = slideNo - 1; - this.updateSlides_(); - } + if (slideNo) { + this.curSlide_ = slideNo - 1; + this.updateSlides_(); + } }; /** * @private */ SlideDeck.prototype.onDomLoaded_ = function(e) { - document.body.classList.add('loaded'); // Add loaded class for templates to use. - - this.slides = this.container.querySelectorAll('slide:not([hidden]):not(.hidden):not(.backdrop)'); - - // If we're on a smartphone, apply special sauce. - if (Modernizr.mq('only screen and (max-device-width: 480px)')) { - // var style = document.createElement('link'); - // style.rel = 'stylesheet'; - // style.type = 'text/css'; - // style.href = this.CSS_DIR_ + 'phone.css'; - // document.querySelector('head').appendChild(style); - - // No need for widescreen layout on a phone. - this.container.classList.remove('layout-widescreen'); - } - - this.loadConfig_(SLIDE_CONFIG); - this.addEventListeners_(); - this.updateSlides_(); - - // Add slide numbers and total slide count metadata to each slide. - var that = this; - for (var i = 0, slide; slide = this.slides[i]; ++i) { - slide.dataset.slideNum = i + 1; - slide.dataset.totalSlides = this.slides.length; - - slide.addEventListener('click', function(e) { - if (document.body.classList.contains('overview')) { - that.loadSlide(this.dataset.slideNum); - e.preventDefault(); - window.setTimeout(function() { - that.toggleOverview(); - }, 500); - } - }, false); - } - - // Note: this needs to come after addEventListeners_(), which adds a - // 'keydown' listener that this controller relies on. - - // Modernizr.touch isn't a sufficient check for devices that support both - // touch and mouse. Create the controller in all cases. - // // Also, no need to set this up if we're on mobile. - // if (!Modernizr.touch) { - this.controller = new SlideController(this); - if (this.controller.isPopup) { - document.body.classList.add('popup'); - } - //} + document.body.classList.add('loaded'); // Add loaded class for templates to + // use. + + this.slides = this.container + .querySelectorAll('slide:not([hidden]):not(.hidden):not(.backdrop)'); + + // If we're on a smartphone, apply special sauce. + if (Modernizr.mq('only screen and (max-device-width: 480px)')) { + // var style = document.createElement('link'); + // style.rel = 'stylesheet'; + // style.type = 'text/css'; + // style.href = this.CSS_DIR_ + 'phone.css'; + // document.querySelector('head').appendChild(style); + + // No need for widescreen layout on a phone. + this.container.classList.remove('layout-widescreen'); + } + + this.loadConfig_(SLIDE_CONFIG); + this.addEventListeners_(); + this.updateSlides_(); + + // Add slide numbers and total slide count metadata to each slide. + var that = this; + for (var i = 0, slide; slide = this.slides[i]; ++i) { + slide.dataset.slideNum = i + 1; + slide.dataset.totalSlides = this.slides.length; + + slide.addEventListener('click', function(e) { + if (document.body.classList.contains('overview')) { + that.loadSlide(this.dataset.slideNum); + e.preventDefault(); + window.setTimeout(function() { + that.toggleOverview(); + }, 500); + } + }, false); + } + + // Note: this needs to come after addEventListeners_(), which adds a + // 'keydown' listener that this controller relies on. + + // Modernizr.touch isn't a sufficient check for devices that support both + // touch and mouse. Create the controller in all cases. + // // Also, no need to set this up if we're on mobile. + // if (!Modernizr.touch) { + this.controller = new SlideController(this); + if (this.controller.isPopup) { + document.body.classList.add('popup'); + } + // } }; /** * @private */ SlideDeck.prototype.addEventListeners_ = function() { - document.addEventListener('keydown', this.onBodyKeyDown_.bind(this), false); - window.addEventListener('popstate', this.onPopState_.bind(this), false); - - // var transEndEventNames = { - // 'WebkitTransition': 'webkitTransitionEnd', - // 'MozTransition': 'transitionend', - // 'OTransition': 'oTransitionEnd', - // 'msTransition': 'MSTransitionEnd', - // 'transition': 'transitionend' - // }; - // - // // Find the correct transitionEnd vendor prefix. - // window.transEndEventName = transEndEventNames[ - // Modernizr.prefixed('transition')]; - // - // // When slides are done transitioning, kickoff loading iframes. - // // Note: we're only looking at a single transition (on the slide). This - // // doesn't include autobuilds the slides may have. Also, if the slide - // // transitions on multiple properties (e.g. not just 'all'), this doesn't - // // handle that case. - // this.container.addEventListener(transEndEventName, function(e) { - // this.enableSlideFrames_(this.curSlide_); - // }.bind(this), false); - - // document.addEventListener('slideenter', function(e) { - // var slide = e.target; - // window.setTimeout(function() { - // this.enableSlideFrames_(e.slideNumber); - // this.enableSlideFrames_(e.slideNumber + 1); - // }.bind(this), 300); - // }.bind(this), false); + document.addEventListener('keydown', this.onBodyKeyDown_.bind(this), false); + window.addEventListener('popstate', this.onPopState_.bind(this), false); + + // var transEndEventNames = { + // 'WebkitTransition': 'webkitTransitionEnd', + // 'MozTransition': 'transitionend', + // 'OTransition': 'oTransitionEnd', + // 'msTransition': 'MSTransitionEnd', + // 'transition': 'transitionend' + // }; + // + // // Find the correct transitionEnd vendor prefix. + // window.transEndEventName = transEndEventNames[ + // Modernizr.prefixed('transition')]; + // + // // When slides are done transitioning, kickoff loading iframes. + // // Note: we're only looking at a single transition (on the slide). This + // // doesn't include autobuilds the slides may have. Also, if the slide + // // transitions on multiple properties (e.g. not just 'all'), this doesn't + // // handle that case. + // this.container.addEventListener(transEndEventName, function(e) { + // this.enableSlideFrames_(this.curSlide_); + // }.bind(this), false); + + // document.addEventListener('slideenter', function(e) { + // var slide = e.target; + // window.setTimeout(function() { + // this.enableSlideFrames_(e.slideNumber); + // this.enableSlideFrames_(e.slideNumber + 1); + // }.bind(this), 300); + // }.bind(this), false); }; /** * @private - * @param {Event} e The pop event. + * @param {Event} + * e The pop event. */ SlideDeck.prototype.onPopState_ = function(e) { - if (e.state != null) { - this.curSlide_ = e.state; - this.updateSlides_(true); - } + if (e.state != null) { + this.curSlide_ = e.state; + this.updateSlides_(true); + } }; /** - * @param {Event} e + * @param {Event} + * e */ SlideDeck.prototype.onBodyKeyDown_ = function(e) { - if (/^(input|textarea)$/i.test(e.target.nodeName) || - e.target.isContentEditable) { - return; - } - - // Forward keydowns to the main slides if we're the popup. - if (this.controller && this.controller.isPopup) { - this.controller.sendMsg({keyCode: e.keyCode}); - } - - switch (e.keyCode) { - case 13: // Enter - if (document.body.classList.contains('overview')) { - this.toggleOverview(); - } - break; - - case 39: // right arrow - case 32: // space - case 34: // PgDn - this.nextSlide(); - e.preventDefault(); - break; - - case 37: // left arrow - case 8: // Backspace - case 33: // PgUp - this.prevSlide(); - e.preventDefault(); - break; - - case 40: // down arrow - this.nextSlide(); - e.preventDefault(); - break; - - case 38: // up arrow - this.prevSlide(); - e.preventDefault(); - break; - - case 72: // H: Toggle code highlighting - document.body.classList.toggle('highlight-code'); - break; - - case 79: // O: Toggle overview - this.toggleOverview(); - break; - - case 80: // P - if (this.controller && this.controller.isPopup) { - document.body.classList.toggle('with-notes'); - } else if (this.controller && !this.controller.popup) { - document.body.classList.toggle('with-notes'); - } - break; - - case 82: // R - // TODO: implement refresh on main slides when popup is refreshed. - break; - - case 27: // ESC: Hide notes and highlighting - document.body.classList.remove('with-notes'); - document.body.classList.remove('highlight-code'); - - if (document.body.classList.contains('overview')) { - this.toggleOverview(); - } - break; - - case 70: // F: Toggle fullscreen - // Only respect 'f' on body. Don't want to capture keys from an . - // Also, ignore browser's fullscreen shortcut (cmd+shift+f) so we don't - // get trapped in fullscreen! - if (e.target == document.body && !(e.shiftKey && e.metaKey)) { - if (document.mozFullScreen !== undefined && !document.mozFullScreen) { - document.body.mozRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } else if (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen) { - document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - document.cancelFullScreen(); - } - } - break; - - case 87: // W: Toggle widescreen - // Only respect 'w' on body. Don't want to capture keys from an . - if (e.target == document.body && !(e.shiftKey && e.metaKey)) { - this.container.classList.toggle('layout-widescreen'); - } - break; - } + if (/^(input|textarea)$/i.test(e.target.nodeName) + || e.target.isContentEditable) { + return; + } + + // Forward keydowns to the main slides if we're the popup. + if (this.controller && this.controller.isPopup) { + this.controller.sendMsg({ + keyCode : e.keyCode + }); + } + + switch (e.keyCode) { + case 13: // Enter + if (document.body.classList.contains('overview')) { + this.toggleOverview(); + } + break; + + case 39: // right arrow + case 32: // space + case 34: // PgDn + this.nextSlide(); + e.preventDefault(); + break; + + case 37: // left arrow + case 8: // Backspace + case 33: // PgUp + this.prevSlide(); + e.preventDefault(); + break; + + case 40: // down arrow + this.nextSlide(); + e.preventDefault(); + break; + + case 38: // up arrow + this.prevSlide(); + e.preventDefault(); + break; + + case 72: // H: Toggle code highlighting + document.body.classList.toggle('highlight-code'); + break; + + case 79: // O: Toggle overview + this.toggleOverview(); + break; + + case 80: // P + if (this.controller && this.controller.isPopup) { + document.body.classList.toggle('with-notes'); + } else if (this.controller && !this.controller.popup) { + document.body.classList.toggle('with-notes'); + } + break; + + case 82: // R + // TODO: implement refresh on main slides when popup is refreshed. + break; + + case 27: // ESC: Hide notes and highlighting + document.body.classList.remove('with-notes'); + document.body.classList.remove('highlight-code'); + + if (document.body.classList.contains('overview')) { + this.toggleOverview(); + } + break; + + case 70: // F: Toggle fullscreen + // Only respect 'f' on body. Don't want to capture keys from an + // . + // Also, ignore browser's fullscreen shortcut (cmd+shift+f) so we + // don't + // get trapped in fullscreen! + if (e.target == document.body && !(e.shiftKey && e.metaKey)) { + if (document.mozFullScreen !== undefined + && !document.mozFullScreen) { + document.body + .mozRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } else if (document.webkitIsFullScreen !== undefined + && !document.webkitIsFullScreen) { + document.body + .webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + document.cancelFullScreen(); + } + } + break; + + case 87: // W: Toggle widescreen + // Only respect 'w' on body. Don't want to capture keys from an + // . + if (e.target == document.body && !(e.shiftKey && e.metaKey)) { + this.container.classList.toggle('layout-widescreen'); + } + break; + } }; /** * */ SlideDeck.prototype.focusOverview_ = function() { - var overview = document.body.classList.contains('overview'); + var overview = document.body.classList.contains('overview'); - for (var i = 0, slide; slide = this.slides[i]; i++) { - slide.style[Modernizr.prefixed('transform')] = overview ? - 'translateZ(-2500px) translate(' + (( i - this.curSlide_ ) * 105) + - '%, 0%)' : ''; - } + for (var i = 0, slide; slide = this.slides[i]; i++) { + slide.style[Modernizr.prefixed('transform')] = overview ? 'translateZ(-2500px) translate(' + + ((i - this.curSlide_) * 105) + '%, 0%)' + : ''; + } }; /** */ SlideDeck.prototype.toggleOverview = function() { - document.body.classList.toggle('overview'); + document.body.classList.toggle('overview'); - this.focusOverview_(); + this.focusOverview_(); }; /** * @private */ SlideDeck.prototype.loadConfig_ = function(config) { - if (!config) { - return; - } - - this.config_ = config; - - var settings = this.config_.settings; - - this.loadTheme_(settings.theme || []); - - if (settings.favIcon) { - this.addFavIcon_(settings.favIcon); - } - - // Prettyprint. Default to on. - if (!!!('usePrettify' in settings) || settings.usePrettify) { - prettyPrint(); - } - - if (settings.analytics) { - this.loadAnalytics_(); - } - - if (settings.fonts) { - this.addFonts_(settings.fonts); - } - - // Builds. Default to on. - if (!!!('useBuilds' in settings) || settings.useBuilds) { - this.makeBuildLists_(); - } - - if (settings.title) { - document.title = settings.title.replace(//, ' '); - if (settings.eventInfo && settings.eventInfo.title) { - document.title += ' - ' + settings.eventInfo.title; - } - document.querySelector('[data-config-title]').innerHTML = settings.title; - } - - if (settings.subtitle) { - document.querySelector('[data-config-subtitle]').innerHTML = settings.subtitle; - } - - if (this.config_.presenters) { - var presenters = this.config_.presenters; - var dataConfigContact = document.querySelector('[data-config-contact]'); - - var html = []; - if (presenters.length == 1) { - var p = presenters[0]; - - var presenterTitle = [p.name]; - if (p.company) { - presenterTitle.push(p.company); - } - html = presenterTitle.join(' - ') + '
'; - - var gplus = p.gplus ? 'g+' + p.gplus.replace(/https?:\/\//, '') + '' : ''; - - var twitter = p.twitter ? 'twitter' + - '' + - p.twitter + '' : ''; - - var www = p.www ? 'www' + p.www.replace(/https?:\/\//, '') + '' : ''; - - var github = p.github ? 'github' + p.github.replace(/https?:\/\//, '') + '' : ''; - - var html2 = [gplus, twitter, www, github].join('
'); - - if (dataConfigContact) { - dataConfigContact.innerHTML = html2; - } - } else { - for (var i = 0, p; p = presenters[i]; ++i) { - html.push(p.name + ' - ' + p.company); - } - html = html.join('
'); - if (dataConfigContact) { - dataConfigContact.innerHTML = html; - } - } - - var dataConfigPresenter = document.querySelector('[data-config-presenter]'); - if (dataConfigPresenter) { - dataConfigPresenter.innerHTML = html; - if (settings.eventInfo) { - var date = settings.eventInfo.date; - var dateInfo = date ? ' - ' : ''; - dataConfigPresenter.innerHTML += settings.eventInfo.title + dateInfo; - } - } - } - - /* Left/Right tap areas. Default to including. */ - if (!!!('enableSlideAreas' in settings) || settings.enableSlideAreas) { - var el = document.createElement('div'); - el.classList.add('slide-area'); - el.id = 'prev-slide-area'; - el.addEventListener('click', this.prevSlide.bind(this), false); - this.container.appendChild(el); - - var el = document.createElement('div'); - el.classList.add('slide-area'); - el.id = 'next-slide-area'; - el.addEventListener('click', this.nextSlide.bind(this), false); - this.container.appendChild(el); - } - - if (Modernizr.touch && (!!!('enableTouch' in settings) || - settings.enableTouch)) { - var self = this; - - // Note: this prevents mobile zoom in/out but prevents iOS from doing - // it's crazy scroll over effect and disaligning the slides. - window.addEventListener('touchstart', function(e) { - e.preventDefault(); - }, false); - - var hammer = new Hammer(this.container); - hammer.ondragend = function(e) { - if (e.direction == 'right' || e.direction == 'down') { - self.prevSlide(); - } else if (e.direction == 'left' || e.direction == 'up') { - self.nextSlide(); - } - }; - } + if (!config) { + return; + } + + this.config_ = config; + + var settings = this.config_.settings; + + this.loadTheme_(settings.theme || []); + + if (settings.favIcon) { + this.addFavIcon_(settings.favIcon); + } + + // Prettyprint. Default to on. + if (!!!('usePrettify' in settings) || settings.usePrettify) { + prettyPrint(); + } + + if (settings.analytics) { + this.loadAnalytics_(); + } + + if (settings.fonts) { + this.addFonts_(settings.fonts); + } + + // Builds. Default to on. + if (!!!('useBuilds' in settings) || settings.useBuilds) { + this.makeBuildLists_(); + } + + if (settings.title) { + document.title = settings.title.replace(//, ' '); + if (settings.eventInfo && settings.eventInfo.title) { + document.title += ' - ' + settings.eventInfo.title; + } + document.querySelector('[data-config-title]').innerHTML = settings.title; + } + + if (settings.subtitle) { + document.querySelector('[data-config-subtitle]').innerHTML = settings.subtitle; + } + + if (this.config_.presenters) { + var presenters = this.config_.presenters; + var dataConfigContact = document.querySelector('[data-config-contact]'); + + var html = []; + if (presenters.length == 1) { + var p = presenters[0]; + + var presenterTitle = [ p.name ]; + if (p.company) { + presenterTitle.push(p.company); + } + html = presenterTitle.join(' - ') + '
'; + + var gplus = p.gplus ? 'g+' + + p.gplus.replace(/https?:\/\//, '') + '' : ''; + + var twitter = p.twitter ? 'twitter' + + '' + + p.twitter + '' : ''; + + var www = p.www ? 'www' + + p.www.replace(/https?:\/\//, '') + '' : ''; + + var github = p.github ? 'github' + p.github.replace(/https?:\/\//, '') + '' : ''; + + var html2 = [ gplus, twitter, www, github ].join('
'); + + if (dataConfigContact) { + dataConfigContact.innerHTML = html2; + } + } else { + for (var i = 0, p; p = presenters[i]; ++i) { + html.push(p.name + ' - ' + p.company); + } + html = html.join('
'); + if (dataConfigContact) { + dataConfigContact.innerHTML = html; + } + } + + var dataConfigPresenter = document + .querySelector('[data-config-presenter]'); + if (dataConfigPresenter) { + dataConfigPresenter.innerHTML = html; + if (settings.eventInfo) { + var date = settings.eventInfo.date; + var dateInfo = date ? ' - ' : ''; + dataConfigPresenter.innerHTML += settings.eventInfo.title + + dateInfo; + } + } + } + + /* Left/Right tap areas. Default to including. */ + if (!!!('enableSlideAreas' in settings) || settings.enableSlideAreas) { + var el = document.createElement('div'); + el.classList.add('slide-area'); + el.id = 'prev-slide-area'; + el.addEventListener('click', this.prevSlide.bind(this), false); + this.container.appendChild(el); + + var el = document.createElement('div'); + el.classList.add('slide-area'); + el.id = 'next-slide-area'; + el.addEventListener('click', this.nextSlide.bind(this), false); + this.container.appendChild(el); + } + + if (Modernizr.touch + && (!!!('enableTouch' in settings) || settings.enableTouch)) { + var self = this; + + // Note: this prevents mobile zoom in/out but prevents iOS from doing + // it's crazy scroll over effect and disaligning the slides. + window.addEventListener('touchstart', function(e) { + e.preventDefault(); + }, false); + + var hammer = new Hammer(this.container); + hammer.ondragend = function(e) { + if (e.direction == 'right' || e.direction == 'down') { + self.prevSlide(); + } else if (e.direction == 'left' || e.direction == 'up') { + self.nextSlide(); + } + }; + } }; /** * @private - * @param {Array.} fonts + * @param {Array. + * } fonts */ SlideDeck.prototype.addFonts_ = function(fonts) { - var el = document.createElement('link'); - el.rel = 'stylesheet'; - el.href = ('https:' == document.location.protocol ? 'https' : 'http') + - '://fonts.googleapis.com/css?family=' + fonts.join('|') + '&v2'; - document.querySelector('head').appendChild(el); + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.href = ('https:' == document.location.protocol ? 'https' : 'http') + + '://fonts.googleapis.com/css?family=' + fonts.join('|') + '&v2'; + document.querySelector('head').appendChild(el); }; /** * @private */ SlideDeck.prototype.buildNextItem_ = function() { - var slide = this.slides[this.curSlide_]; - var toBuild = slide.querySelector('.to-build'); - var built = slide.querySelector('.build-current'); - - if (built) { - built.classList.remove('build-current'); - if (built.classList.contains('fade')) { - built.classList.add('build-fade'); - } - } - - if (!toBuild) { - var items = slide.querySelectorAll('.build-fade'); - for (var j = 0, item; item = items[j]; j++) { - item.classList.remove('build-fade'); - } - return false; - } - - toBuild.classList.remove('to-build'); - toBuild.classList.add('build-current'); - - return true; + var slide = this.slides[this.curSlide_]; + var toBuild = slide.querySelector('.to-build'); + var built = slide.querySelector('.build-current'); + + if (built) { + built.classList.remove('build-current'); + if (built.classList.contains('fade')) { + built.classList.add('build-fade'); + } + } + + if (!toBuild) { + var items = slide.querySelectorAll('.build-fade'); + for (var j = 0, item; item = items[j]; j++) { + item.classList.remove('build-fade'); + } + return false; + } + + toBuild.classList.remove('to-build'); + toBuild.classList.add('build-current'); + + return true; }; /** - * @param {boolean=} opt_dontPush + * @param {boolean=} + * opt_dontPush */ SlideDeck.prototype.prevSlide = function(opt_dontPush) { - if (this.curSlide_ > 0) { - var bodyClassList = document.body.classList; - bodyClassList.remove('highlight-code'); - - // Toggle off speaker notes if they're showing when we move backwards on the - // main slides. If we're the speaker notes popup, leave them up. - if (this.controller && !this.controller.isPopup) { - bodyClassList.remove('with-notes'); - } else if (!this.controller) { - bodyClassList.remove('with-notes'); - } - - this.prevSlide_ = this.curSlide_--; - - this.updateSlides_(opt_dontPush); - } + if (this.curSlide_ > 0) { + var bodyClassList = document.body.classList; + bodyClassList.remove('highlight-code'); + + // Toggle off speaker notes if they're showing when we move backwards on + // the + // main slides. If we're the speaker notes popup, leave them up. + if (this.controller && !this.controller.isPopup) { + bodyClassList.remove('with-notes'); + } else if (!this.controller) { + bodyClassList.remove('with-notes'); + } + + this.prevSlide_ = this.curSlide_--; + + this.updateSlides_(opt_dontPush); + } }; /** - * @param {boolean=} opt_dontPush + * @param {boolean=} + * opt_dontPush */ SlideDeck.prototype.nextSlide = function(opt_dontPush) { - if (!document.body.classList.contains('overview') && this.buildNextItem_()) { - return; - } - - if (this.curSlide_ < this.slides.length - 1) { - var bodyClassList = document.body.classList; - bodyClassList.remove('highlight-code'); - - // Toggle off speaker notes if they're showing when we advanced on the main - // slides. If we're the speaker notes popup, leave them up. - if (this.controller && !this.controller.isPopup) { - bodyClassList.remove('with-notes'); - } else if (!this.controller) { - bodyClassList.remove('with-notes'); - } - - this.prevSlide_ = this.curSlide_++; - - this.updateSlides_(opt_dontPush); - } + if (!document.body.classList.contains('overview') && this.buildNextItem_()) { + return; + } + + if (this.curSlide_ < this.slides.length - 1) { + var bodyClassList = document.body.classList; + bodyClassList.remove('highlight-code'); + + // Toggle off speaker notes if they're showing when we advanced on the + // main + // slides. If we're the speaker notes popup, leave them up. + if (this.controller && !this.controller.isPopup) { + bodyClassList.remove('with-notes'); + } else if (!this.controller) { + bodyClassList.remove('with-notes'); + } + + this.prevSlide_ = this.curSlide_++; + + this.updateSlides_(opt_dontPush); + } }; /* Slide events */ /** * Triggered when a slide enter/leave event should be dispatched. - * - * @param {string} type The type of event to trigger - * (e.g. 'slideenter', 'slideleave'). - * @param {number} slideNo The index of the slide that is being left. + * + * @param {string} + * type The type of event to trigger (e.g. 'slideenter', + * 'slideleave'). + * @param {number} + * slideNo The index of the slide that is being left. */ SlideDeck.prototype.triggerSlideEvent = function(type, slideNo) { - var el = this.getSlideEl_(slideNo); - if (!el) { - return; - } - - // Call onslideenter/onslideleave if the attribute is defined on this slide. - var func = el.getAttribute(type); - if (func) { - new Function(func).call(el); // TODO: Don't use new Function() :( - } - - // Dispatch event to listeners setup using addEventListener. - var evt = document.createEvent('Event'); - evt.initEvent(type, true, true); - evt.slideNumber = slideNo + 1; // Make it readable - evt.slide = el; - - el.dispatchEvent(evt); + var el = this.getSlideEl_(slideNo); + if (!el) { + return; + } + + // Call onslideenter/onslideleave if the attribute is defined on this slide. + var func = el.getAttribute(type); + if (func) { + new Function(func).call(el); // TODO: Don't use new Function() :( + } + + // Dispatch event to listeners setup using addEventListener. + var evt = document.createEvent('Event'); + evt.initEvent(type, true, true); + evt.slideNumber = slideNo + 1; // Make it readable + evt.slide = el; + + el.dispatchEvent(evt); }; /** * @private */ SlideDeck.prototype.updateSlides_ = function(opt_dontPush) { - var dontPush = opt_dontPush || false; - - var curSlide = this.curSlide_; - for (var i = 0; i < this.slides.length; ++i) { - switch (i) { - case curSlide - 2: - this.updateSlideClass_(i, 'far-past'); - break; - case curSlide - 1: - this.updateSlideClass_(i, 'past'); - break; - case curSlide: - this.updateSlideClass_(i, 'current'); - break; - case curSlide + 1: - this.updateSlideClass_(i, 'next'); - break; - case curSlide + 2: - this.updateSlideClass_(i, 'far-next'); - break; - default: - this.updateSlideClass_(i); - break; - } - }; - - this.triggerSlideEvent('slideleave', this.prevSlide_); - this.triggerSlideEvent('slideenter', curSlide); - -// window.setTimeout(this.disableSlideFrames_.bind(this, curSlide - 2), 301); -// -// this.enableSlideFrames_(curSlide - 1); // Previous slide. -// this.enableSlideFrames_(curSlide + 1); // Current slide. -// this.enableSlideFrames_(curSlide + 2); // Next slide. - - // Enable current slide's iframes (needed for page loat at current slide). - this.enableSlideFrames_(curSlide + 1); - - // No way to tell when all slide transitions + auto builds are done. - // Give ourselves a good buffer to preload the next slide's iframes. - window.setTimeout(this.enableSlideFrames_.bind(this, curSlide + 2), 1000); - - this.updateHash_(dontPush); - - if (document.body.classList.contains('overview')) { - this.focusOverview_(); - return; - } + var dontPush = opt_dontPush || false; + + var curSlide = this.curSlide_; + for (var i = 0; i < this.slides.length; ++i) { + switch (i) { + case curSlide - 2: + this.updateSlideClass_(i, 'far-past'); + break; + case curSlide - 1: + this.updateSlideClass_(i, 'past'); + break; + case curSlide: + this.updateSlideClass_(i, 'current'); + break; + case curSlide + 1: + this.updateSlideClass_(i, 'next'); + break; + case curSlide + 2: + this.updateSlideClass_(i, 'far-next'); + break; + default: + this.updateSlideClass_(i); + break; + } + } + ; + + this.triggerSlideEvent('slideleave', this.prevSlide_); + this.triggerSlideEvent('slideenter', curSlide); + + // window.setTimeout(this.disableSlideFrames_.bind(this, curSlide - 2), + // 301); + // + // this.enableSlideFrames_(curSlide - 1); // Previous slide. + // this.enableSlideFrames_(curSlide + 1); // Current slide. + // this.enableSlideFrames_(curSlide + 2); // Next slide. + + // Enable current slide's iframes (needed for page loat at current slide). + this.enableSlideFrames_(curSlide + 1); + + // No way to tell when all slide transitions + auto builds are done. + // Give ourselves a good buffer to preload the next slide's iframes. + window.setTimeout(this.enableSlideFrames_.bind(this, curSlide + 2), 1000); + + this.updateHash_(dontPush); + + if (document.body.classList.contains('overview')) { + this.focusOverview_(); + return; + } }; /** * @private - * @param {number} slideNo + * @param {number} + * slideNo */ SlideDeck.prototype.enableSlideFrames_ = function(slideNo) { - var el = this.slides[slideNo - 1]; - if (!el) { - return; - } - - var frames = el.querySelectorAll('iframe'); - for (var i = 0, frame; frame = frames[i]; i++) { - this.enableFrame_(frame); - } + var el = this.slides[slideNo - 1]; + if (!el) { + return; + } + + var frames = el.querySelectorAll('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + this.enableFrame_(frame); + } }; /** * @private - * @param {number} slideNo + * @param {number} + * slideNo */ SlideDeck.prototype.enableFrame_ = function(frame) { - var src = frame.dataset.src; - if (src && frame.src != src) { - frame.src = src; - } + var src = frame.dataset.src; + if (src && frame.src != src) { + frame.src = src; + } }; /** * @private - * @param {number} slideNo + * @param {number} + * slideNo */ SlideDeck.prototype.disableSlideFrames_ = function(slideNo) { - var el = this.slides[slideNo - 1]; - if (!el) { - return; - } - - var frames = el.querySelectorAll('iframe'); - for (var i = 0, frame; frame = frames[i]; i++) { - this.disableFrame_(frame); - } + var el = this.slides[slideNo - 1]; + if (!el) { + return; + } + + var frames = el.querySelectorAll('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + this.disableFrame_(frame); + } }; /** * @private - * @param {Node} frame + * @param {Node} + * frame */ SlideDeck.prototype.disableFrame_ = function(frame) { - frame.src = 'about:blank'; + frame.src = 'about:blank'; }; /** * @private - * @param {number} slideNo + * @param {number} + * slideNo */ SlideDeck.prototype.getSlideEl_ = function(no) { - if ((no < 0) || (no >= this.slides.length)) { - return null; - } else { - return this.slides[no]; - } + if ((no < 0) || (no >= this.slides.length)) { + return null; + } else { + return this.slides[no]; + } }; /** * @private - * @param {number} slideNo - * @param {string} className + * @param {number} + * slideNo + * @param {string} + * className */ SlideDeck.prototype.updateSlideClass_ = function(slideNo, className) { - var el = this.getSlideEl_(slideNo); + var el = this.getSlideEl_(slideNo); - if (!el) { - return; - } + if (!el) { + return; + } - if (className) { - el.classList.add(className); - } + if (className) { + el.classList.add(className); + } - for (var i = 0, slideClass; slideClass = this.SLIDE_CLASSES_[i]; ++i) { - if (className != slideClass) { - el.classList.remove(slideClass); - } - } + for (var i = 0, slideClass; slideClass = this.SLIDE_CLASSES_[i]; ++i) { + if (className != slideClass) { + el.classList.remove(slideClass); + } + } }; /** * @private */ -SlideDeck.prototype.makeBuildLists_ = function () { - for (var i = this.curSlide_, slide; slide = this.slides[i]; ++i) { - var items = slide.querySelectorAll('.build > *'); - for (var j = 0, item; item = items[j]; ++j) { - if (item.classList) { - item.classList.add('to-build'); - if (item.parentNode.classList.contains('fade')) { - item.classList.add('fade'); - } - } - } - } +SlideDeck.prototype.makeBuildLists_ = function() { + for (var i = this.curSlide_, slide; slide = this.slides[i]; ++i) { + var items = slide.querySelectorAll('.build > *'); + for (var j = 0, item; item = items[j]; ++j) { + if (item.classList) { + item.classList.add('to-build'); + if (item.parentNode.classList.contains('fade')) { + item.classList.add('fade'); + } + } + } + } }; /** * @private - * @param {boolean} dontPush + * @param {boolean} + * dontPush */ SlideDeck.prototype.updateHash_ = function(dontPush) { - if (!dontPush) { - var slideNo = this.curSlide_ + 1; - var hash = '#' + slideNo; - if (window.history.pushState) { - window.history.pushState(this.curSlide_, 'Slide ' + slideNo, hash); - } else { - window.location.replace(hash); - } - - // Record GA hit on this slide. - window['_gaq'] && window['_gaq'].push(['_trackPageview', - document.location.href]); - } + if (!dontPush) { + var slideNo = this.curSlide_ + 1; + var hash = '#' + slideNo; + if (window.history.pushState) { + window.history.pushState(this.curSlide_, 'Slide ' + slideNo, hash); + } else { + window.location.replace(hash); + } + + // Record GA hit on this slide. + window['_gaq'] + && window['_gaq'].push([ '_trackPageview', + document.location.href ]); + } }; - /** * @private - * @param {string} favIcon + * @param {string} + * favIcon */ SlideDeck.prototype.addFavIcon_ = function(favIcon) { - var el = document.createElement('link'); - el.rel = 'icon'; - el.type = 'image/png'; - el.href = favIcon; - document.querySelector('head').appendChild(el); + var el = document.createElement('link'); + el.rel = 'icon'; + el.type = 'image/png'; + el.href = favIcon; + document.querySelector('head').appendChild(el); }; /** * @private - * @param {string} theme + * @param {string} + * theme */ SlideDeck.prototype.loadTheme_ = function(theme) { - var styles = []; - if (theme.constructor.name === 'String') { - styles.push(theme); - } else { - styles = theme; - } - - for (var i = 0, style; themeUrl = styles[i]; i++) { - var style = document.createElement('link'); - style.rel = 'stylesheet'; - style.type = 'text/css'; - if (themeUrl.indexOf('http') == -1) { - style.href = this.CSS_DIR_ + themeUrl + '.css'; - } else { - style.href = themeUrl; - } - document.querySelector('head').appendChild(style); - } + var styles = []; + if (theme.constructor.name === 'String') { + styles.push(theme); + } else { + styles = theme; + } + + for (var i = 0, style; themeUrl = styles[i]; i++) { + var style = document.createElement('link'); + style.rel = 'stylesheet'; + style.type = 'text/css'; + if (themeUrl.indexOf('http') == -1) { + style.href = this.CSS_DIR_ + themeUrl + '.css'; + } else { + style.href = themeUrl; + } + document.querySelector('head').appendChild(style); + } }; /** * @private */ SlideDeck.prototype.loadAnalytics_ = function() { - var _gaq = window['_gaq'] || []; - _gaq.push(['_setAccount', this.config_.settings.analytics]); - _gaq.push(['_trackPageview']); - - (function() { - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); - })(); + var _gaq = window['_gaq'] || []; + _gaq.push([ '_setAccount', this.config_.settings.analytics ]); + _gaq.push([ '_trackPageview' ]); + + (function() { + var ga = document.createElement('script'); + ga.type = 'text/javascript'; + ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' + : 'http://www') + + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(ga, s); + })(); }; - // Polyfill missing APIs (if we need to), then create the slide deck. // iOS < 5 needs classList, dataset, and window.matchMedia. Modernizr contains // the last one. (function() { - Modernizr.load({ - test: !!document.body.classList && !!document.body.dataset, - nope: ['js/polyfills/classList.min.js', 'js/polyfills/dataset.min.js'], - complete: function() { - window.slidedeck = new SlideDeck(); - } - }); + Modernizr + .load({ + test : !!document.body.classList && !!document.body.dataset, + nope : [ 'js/polyfills/classList.min.js', + 'js/polyfills/dataset.min.js' ], + complete : function() { + window.slidedeck = new SlideDeck(); + } + }); })(); diff --git a/js/slides.js b/js/slides.js index 3f6306e..156fb03 100644 --- a/js/slides.js +++ b/js/slides.js @@ -1,5 +1,5 @@ -require(['order!../slide_config', 'order!modernizr.custom.45394', - 'order!prettify/prettify', 'order!hammer', 'order!slide-controller', - 'order!slide-deck'], function(someModule) { +require([ 'order!../slide_config', 'order!modernizr.custom.45394', + 'order!prettify/prettify', 'order!hammer', 'order!slide-controller', + 'order!slide-deck' ], function(someModule) { }); -- cgit v1.2.3