diff options
Diffstat (limited to 'js/slides.js')
-rw-r--r-- | js/slides.js | 708 |
1 files changed, 11 insertions, 697 deletions
diff --git a/js/slides.js b/js/slides.js index 9ad0290..1af4bd5 100644 --- a/js/slides.js +++ b/js/slides.js | |||
@@ -1,701 +1,15 @@ | |||
1 | document.cancelFullScreen = document.webkitCancelFullScreen || | ||
2 | document.mozCancelFullScreen; | ||
3 | |||
4 | /** | 1 | /** |
5 | * @constructor | 2 | * ADD stuff here |
6 | */ | 3 | */ |
7 | function SlideDeck(el) { | ||
8 | this.curSlide_ = 0; | ||
9 | this.prevSlide_ = 0; | ||
10 | this.config_ = null; | ||
11 | this.container = el || document.querySelector('slides'); | ||
12 | this.slides = []; | ||
13 | this.controller = null; | ||
14 | |||
15 | this.getCurrentSlideFromHash_(); | ||
16 | |||
17 | // Call this explicitly. Modernizr.load won't be done until after DOM load. | ||
18 | this.onDomLoaded_.bind(this)(); | ||
19 | } | ||
20 | |||
21 | /** | ||
22 | * @const | ||
23 | * @private | ||
24 | */ | ||
25 | SlideDeck.prototype.SLIDE_CLASSES_ = [ | ||
26 | 'far-past', 'past', 'current', 'next', 'far-next']; | ||
27 | |||
28 | /** | ||
29 | * @const | ||
30 | * @private | ||
31 | */ | ||
32 | SlideDeck.prototype.CSS_DIR_ = 'theme/css/'; | ||
33 | |||
34 | /** | ||
35 | * @private | ||
36 | */ | ||
37 | SlideDeck.prototype.getCurrentSlideFromHash_ = function() { | ||
38 | var slideNo = parseInt(document.location.hash.substr(1)); | ||
39 | |||
40 | if (slideNo) { | ||
41 | this.curSlide_ = slideNo - 1; | ||
42 | } else { | ||
43 | this.curSlide_ = 0; | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * @private | ||
49 | */ | ||
50 | SlideDeck.prototype.onDomLoaded_ = function(e) { | ||
51 | document.body.classList.add('loaded'); // Fade in deck. | ||
52 | |||
53 | this.slides = this.container.querySelectorAll('slide:not([hidden]):not(.backdrop)'); | ||
54 | |||
55 | // If we're on a smartphone, apply special sauce. | ||
56 | if (Modernizr.mq('only screen and (max-device-width: 480px)')) { | ||
57 | // var style = document.createElement('link'); | ||
58 | // style.rel = 'stylesheet'; | ||
59 | // style.type = 'text/css'; | ||
60 | // style.href = this.CSS_DIR_ + 'phone.css'; | ||
61 | // document.querySelector('head').appendChild(style); | ||
62 | |||
63 | // No need for widescreen layout on a phone. | ||
64 | this.container.classList.remove('layout-widescreen'); | ||
65 | } | ||
66 | |||
67 | this.loadConfig_(SLIDE_CONFIG); | ||
68 | this.addEventListeners_(); | ||
69 | this.updateSlides_(); | ||
70 | |||
71 | // Add slide numbers and total slide count metadata to each slide. | ||
72 | for (var i = 0, slide; slide = this.slides[i]; ++i) { | ||
73 | slide.dataset.slideNum = i + 1; | ||
74 | slide.dataset.totalSlides = this.slides.length; | ||
75 | } | ||
76 | |||
77 | // Note: this needs to come after addEventListeners_(), which adds a | ||
78 | // 'keydown' listener that this controller relies on. | ||
79 | // Also, no need to set this up if we're on mobile. | ||
80 | if (!Modernizr.touch) { | ||
81 | this.controller = new SlideController(this); | ||
82 | if (this.controller.isPopup) { | ||
83 | document.body.classList.add('popup'); | ||
84 | } | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * @private | ||
90 | */ | ||
91 | SlideDeck.prototype.addEventListeners_ = function() { | ||
92 | document.addEventListener('keydown', this.onBodyKeyDown_.bind(this), false); | ||
93 | window.addEventListener('popstate', this.onPopState_.bind(this), false); | ||
94 | |||
95 | // var transEndEventNames = { | ||
96 | // 'WebkitTransition': 'webkitTransitionEnd', | ||
97 | // 'MozTransition': 'transitionend', | ||
98 | // 'OTransition': 'oTransitionEnd', | ||
99 | // 'msTransition': 'MSTransitionEnd', | ||
100 | // 'transition': 'transitionend' | ||
101 | // }; | ||
102 | // | ||
103 | // // Find the correct transitionEnd vendor prefix. | ||
104 | // window.transEndEventName = transEndEventNames[ | ||
105 | // Modernizr.prefixed('transition')]; | ||
106 | // | ||
107 | // // When slides are done transitioning, kickoff loading iframes. | ||
108 | // // Note: we're only looking at a single transition (on the slide). This | ||
109 | // // doesn't include autobuilds the slides may have. Also, if the slide | ||
110 | // // transitions on multiple properties (e.g. not just 'all'), this doesn't | ||
111 | // // handle that case. | ||
112 | // this.container.addEventListener(transEndEventName, function(e) { | ||
113 | // this.enableSlideFrames_(this.curSlide_); | ||
114 | // }.bind(this), false); | ||
115 | |||
116 | // document.addEventListener('slideenter', function(e) { | ||
117 | // var slide = e.target; | ||
118 | // window.setTimeout(function() { | ||
119 | // this.enableSlideFrames_(e.slideNumber); | ||
120 | // this.enableSlideFrames_(e.slideNumber + 1); | ||
121 | // }.bind(this), 300); | ||
122 | // }.bind(this), false); | ||
123 | }; | ||
124 | |||
125 | /** | ||
126 | * @private | ||
127 | * @param {Event} e The pop event. | ||
128 | */ | ||
129 | SlideDeck.prototype.onPopState_ = function(e) { | ||
130 | if (e.state != null) { | ||
131 | this.curSlide_ = e.state; | ||
132 | this.updateSlides_(true); | ||
133 | } | ||
134 | }; | ||
135 | |||
136 | /** | ||
137 | * @param {Event} e | ||
138 | */ | ||
139 | SlideDeck.prototype.onBodyKeyDown_ = function(e) { | ||
140 | if (/^(input|textarea)$/i.test(e.target.nodeName) || | ||
141 | e.target.isContentEditable) { | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | // Forward keydowns to the main slides if we're the popup. | ||
146 | if (this.controller && this.controller.isPopup) { | ||
147 | this.controller.sendMsg({keyCode: e.keyCode}); | ||
148 | } | ||
149 | |||
150 | switch (e.keyCode) { | ||
151 | case 39: // right arrow | ||
152 | case 32: // space | ||
153 | case 34: // PgDn | ||
154 | this.nextSlide(); | ||
155 | e.preventDefault(); | ||
156 | break; | ||
157 | |||
158 | case 37: // left arrow | ||
159 | case 8: // Backspace | ||
160 | case 33: // PgUp | ||
161 | this.prevSlide(); | ||
162 | e.preventDefault(); | ||
163 | break; | ||
164 | |||
165 | case 40: // down arrow | ||
166 | //if (this.isChromeVoxActive()) { | ||
167 | // speakNextItem(); | ||
168 | //} else { | ||
169 | this.nextSlide(); | ||
170 | //} | ||
171 | e.preventDefault(); | ||
172 | break; | ||
173 | |||
174 | case 38: // up arrow | ||
175 | //if (this.isChromeVoxActive()) { | ||
176 | // speakPrevItem(); | ||
177 | //} else { | ||
178 | this.prevSlide(); | ||
179 | //} | ||
180 | e.preventDefault(); | ||
181 | break; | ||
182 | |||
183 | case 72: // H | ||
184 | document.body.classList.toggle('highlight-code'); | ||
185 | break; | ||
186 | |||
187 | case 80: // P | ||
188 | if (this.controller && this.controller.isPopup) { | ||
189 | document.body.classList.toggle('with-notes'); | ||
190 | } else if (this.controller && !this.controller.popup) { | ||
191 | document.body.classList.toggle('with-notes'); | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case 82: // R | ||
196 | // TODO: implement refresh on main slides when popup is refreshed. | ||
197 | break; | ||
198 | |||
199 | case 27: // ESC | ||
200 | document.body.classList.remove('with-notes'); | ||
201 | document.body.classList.remove('highlight-code'); | ||
202 | break; | ||
203 | |||
204 | case 70: // F | ||
205 | // Only respect 'f' on body. Don't want to capture keys from an <input>. | ||
206 | // Also, ignore browser's fullscreen shortcut (cmd+shift+f) so we don't | ||
207 | // get trapped in fullscreen! | ||
208 | if (e.target == document.body && !(e.shiftKey && e.metaKey)) { | ||
209 | if (document.mozFullScreen !== undefined && !document.mozFullScreen) { | ||
210 | document.body.mozRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); | ||
211 | } else if (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen) { | ||
212 | document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); | ||
213 | } else { | ||
214 | document.cancelFullScreen(); | ||
215 | } | ||
216 | } | ||
217 | break; | ||
218 | } | ||
219 | }; | ||
220 | |||
221 | /** | ||
222 | * @private | ||
223 | */ | ||
224 | SlideDeck.prototype.loadConfig_ = function(config) { | ||
225 | if (!config) { | ||
226 | return; | ||
227 | } | ||
228 | |||
229 | this.config_ = config; | ||
230 | |||
231 | var settings = this.config_.settings; | ||
232 | |||
233 | this.loadTheme_(settings.theme || []); | ||
234 | |||
235 | if (settings.favIcon) { | ||
236 | this.addFavIcon_(settings.favIcon); | ||
237 | } | ||
238 | |||
239 | // Prettyprint. Default to on. | ||
240 | if (!!!('usePrettify' in settings) || settings.usePrettify) { | ||
241 | prettyPrint(); | ||
242 | } | ||
243 | |||
244 | if (settings.analytics) { | ||
245 | this.loadAnalytics_(); | ||
246 | } | ||
247 | |||
248 | if (settings.fonts) { | ||
249 | this.addFonts_(settings.fonts); | ||
250 | } | ||
251 | |||
252 | // Builds. Default to on. | ||
253 | if (!!!('useBuilds' in settings) || settings.useBuilds) { | ||