diff options
-rw-r--r-- | js/slide-controller.js | 41 | ||||
-rw-r--r-- | js/slides.js | 100 | ||||
-rw-r--r-- | slide_config.js | 8 | ||||
-rw-r--r-- | template.html | 6 |
4 files changed, 112 insertions, 43 deletions
diff --git a/js/slide-controller.js b/js/slide-controller.js index e2f8bf2..bdbb670 100644 --- a/js/slide-controller.js +++ b/js/slide-controller.js | |||
@@ -1,3 +1,7 @@ | |||
1 | (function(window) { | ||
2 | |||
3 | var ORIGIN = location.protocol + '//' + location.host; | ||
4 | |||
1 | function SlideController(slideDeck) { | 5 | function SlideController(slideDeck) { |
2 | this.deck_ = slideDeck; | 6 | this.deck_ = slideDeck; |
3 | this.win_ = null; | 7 | this.win_ = null; |
@@ -21,34 +25,41 @@ SlideController.MOVE_RIGHT = 1; | |||
21 | SlideController.prototype.onMessage_ = function(e) { | 25 | SlideController.prototype.onMessage_ = function(e) { |
22 | var data = e.data; | 26 | var data = e.data; |
23 | 27 | ||
24 | // It would be dope if FF implemented location.origin. | 28 | // Restrict messages to being from this origin. Allow local developmet |
25 | if (e.origin != location.protocol + '//' + location.host) { | 29 | // from file:// though. |
30 | // TODO: It would be dope if FF implemented location.origin! | ||
31 | if (e.origin != ORIGIN && ORIGIN != 'file://') { | ||
26 | alert('Someone tried to postMessage from an unknown origin'); | 32 | alert('Someone tried to postMessage from an unknown origin'); |
27 | return; | 33 | return; |
28 | } | 34 | } |
29 | 35 | ||
30 | if (e.source.location.hostname != 'localhost') { | 36 | // if (e.source.location.hostname != 'localhost') { |
31 | alert('Someone tried to postMessage from an unknown origin'); | 37 | // alert('Someone tried to postMessage from an unknown origin'); |
32 | return; | 38 | // return; |
33 | } | 39 | // } |
34 | 40 | ||
35 | if ('slideDirection' in data) { | 41 | if ('keyCode' in data) { |
36 | if (data.slideDirection == SlideController.MOVE_LEFT) { | 42 | var evt = document.createEvent('Event'); |
37 | this.deck_.prevSlide(); | 43 | evt.initEvent('keydown', true, true); |
38 | } else { | 44 | evt.keyCode = data.keyCode; |
39 | this.deck_.nextSlide(); | 45 | document.dispatchEvent(evt); |
40 | } | ||
41 | } | 46 | } |
42 | }; | 47 | }; |
43 | 48 | ||
44 | SlideController.prototype.sendMsg = function(msg) { | 49 | SlideController.prototype.sendMsg = function(msg) { |
45 | // // Send message to popup window. | 50 | // // Send message to popup window. |
46 | // if (this.win_) { | 51 | // if (this.win_) { |
47 | // this.win_.postMessage(msg, location.protocol + '//' + location.host); | 52 | // this.win_.postMessage(msg, ORIGIN); |
48 | // } | 53 | // } |
54 | |||
49 | // Send message to main window. | 55 | // Send message to main window. |
50 | if (window.opener) { | 56 | if (window.opener) { |
51 | // It would be dope if FF implemented location.origin. | 57 | // TODO: It would be dope if FF implemented location.origin. |
52 | window.opener.postMessage(msg, location.protocol + '//' + location.host); | 58 | window.opener.postMessage(msg, '*'); |
53 | } | 59 | } |
54 | }; | 60 | }; |
61 | |||
62 | window.SlideController = SlideController; | ||
63 | |||
64 | })(window); | ||
65 | |||
diff --git a/js/slides.js b/js/slides.js index 0faf06b..7afe0cf 100644 --- a/js/slides.js +++ b/js/slides.js | |||
@@ -14,6 +14,7 @@ function SlideDeck() { | |||
14 | this.slides = []; | 14 | this.slides = []; |
15 | this.config_ = null; | 15 | this.config_ = null; |
16 | this.controller_ = null; | 16 | this.controller_ = null; |
17 | this.IS_POPUP_ = window.opener; | ||
17 | 18 | ||
18 | this.getCurrentSlideFromHash_(); | 19 | this.getCurrentSlideFromHash_(); |
19 | 20 | ||
@@ -49,6 +50,39 @@ SlideDeck.prototype.getCurrentSlideFromHash_ = function() { | |||
49 | } | 50 | } |
50 | }; | 51 | }; |
51 | 52 | ||
53 | SlideDeck.prototype.loadPresenterMode = function() { | ||
54 | var params = location.search.substring(1).split('&').map(function(el) { | ||
55 | return el.split('='); | ||
56 | }); | ||
57 | |||
58 | var presentMe = null; | ||
59 | for (var i = 0, param; param = params[i]; ++i) { | ||
60 | if (param[0].toLowerCase() == 'presentme') { | ||
61 | presentMe = param[1] == 'true'; | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | if (presentMe !== null) { | ||
67 | localStorage.ENABLE_PRESENTOR_MODE = presentMe; | ||
68 | location.href = location.pathname; | ||
69 | } | ||
70 | |||
71 | // Turn on presenter mode? | ||
72 | if (localStorage.getItem('ENABLE_PRESENTOR_MODE') && | ||
73 | JSON.parse(localStorage.getItem('ENABLE_PRESENTOR_MODE'))) { | ||
74 | this.controller_ = new SlideController(this); | ||
75 | |||
76 | // Loading in the popup? Trigger the hotkey for turning presenter mode on. | ||
77 | if (this.IS_POPUP_) { | ||
78 | var evt = document.createEvent('Event'); | ||
79 | evt.initEvent('keydown', true, true); | ||
80 | evt.keyCode = 'P'.charCodeAt(0); | ||
81 | document.dispatchEvent(evt); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
52 | /** | 86 | /** |
53 | * @private | 87 | * @private |
54 | */ | 88 | */ |
@@ -70,7 +104,6 @@ SlideDeck.prototype.onDomLoaded_ = function(e) { | |||
70 | document.querySelector('slides').classList.remove('layout-widescreen'); | 104 | document.querySelector('slides').classList.remove('layout-widescreen'); |
71 | } | 105 | } |
72 | 106 | ||
73 | // Load config. | ||
74 | this.loadConfig_(SLIDE_CONFIG); | 107 | this.loadConfig_(SLIDE_CONFIG); |
75 | this.addEventListeners_(); | 108 | this.addEventListeners_(); |
76 | this.updateSlides_(); | 109 | this.updateSlides_(); |
@@ -85,6 +118,10 @@ SlideDeck.prototype.onDomLoaded_ = function(e) { | |||
85 | [].forEach.call(document.querySelectorAll('a'), function(a) { | 118 | [].forEach.call(document.querySelectorAll('a'), function(a) { |
86 | a.target = '_blank'; | 119 | a.target = '_blank'; |
87 | }); | 120 | }); |
121 | |||
122 | // Note: this needs to come after addEventListeners_(), which adds a | ||
123 | // 'keydown' listener that this method relies on. | ||
124 | this.loadPresenterMode(); | ||
88 | }; | 125 | }; |
89 | 126 | ||
90 | /** | 127 | /** |
@@ -115,6 +152,11 @@ SlideDeck.prototype.onBodyKeyDown_ = function(e) { | |||
115 | return; | 152 | return; |
116 | } | 153 | } |
117 | 154 | ||
155 | // Forward keydown to the main slides if we're the popup. | ||
156 | if (this.controller_ && this.IS_POPUP_) { | ||
157 | this.controller_.sendMsg({keyCode: e.keyCode}); | ||
158 | } | ||
159 | |||
118 | switch (e.keyCode) { | 160 | switch (e.keyCode) { |
119 | case 39: // right arrow | 161 | case 39: // right arrow |
120 | case 32: // space | 162 | case 32: // space |
@@ -153,14 +195,20 @@ SlideDeck.prototype.onBodyKeyDown_ = function(e) { | |||
153 | break; | 195 | break; |
154 | 196 | ||
155 | case 80: // P | 197 | case 80: // P |
156 | // If this slide contains notes, toggle them. | 198 | if (this.controller_ && this.IS_POPUP_) { |
157 | //if (this.slides_[this.curSlide_].querySelector('.note')) { | ||
158 | document.body.classList.toggle('with-notes'); | 199 | document.body.classList.toggle('with-notes'); |
159 | //} | 200 | } else if (!this.controller_) { |
201 | document.body.classList.toggle('with-notes'); | ||
202 | } | ||
203 | break; | ||
204 | |||
205 | case 82: // R | ||
206 | // TODO: implement refresh on main slides when popup is refreshed. | ||
160 | break; | 207 | break; |
161 | 208 | ||
162 | case 27: // ESC | 209 | case 27: // ESC |
163 | document.body.classList.remove('with-notes'); | 210 | document.body.classList.remove('with-notes'); |
211 | document.body.classList.remove('highlight-code'); | ||
164 | break; | 212 | break; |
165 | 213 | ||
166 | case 70: // F | 214 | case 70: // F |
@@ -287,10 +335,6 @@ SlideDeck.prototype.loadConfig_ = function(config) { | |||
287 | } | 335 | } |
288 | }; | 336 | }; |
289 | } | 337 | } |
290 | |||
291 | if (!!('enableSpeakerNotes' in settings) && settings.enableSpeakerNotes) { | ||
292 | this.controller_ = new SlideController(this); | ||
293 | } | ||
294 | }; | 338 | }; |
295 | 339 | ||
296 | /** | 340 | /** |
@@ -343,17 +387,20 @@ SlideDeck.prototype.buildNextItem_ = function() { | |||
343 | */ | 387 | */ |
344 | SlideDeck.prototype.prevSlide = function(opt_dontPush) { | 388 | SlideDeck.prototype.prevSlide = function(opt_dontPush) { |
345 | if (this.curSlide_ > 0) { | 389 | if (this.curSlide_ > 0) { |
346 | // Toggle off speaker notes and/or highlighted code if they're showing | 390 | var bodyClassList = document.body.classList; |
347 | // when we advanced. If we're the speaker notes popup, leave this put. | 391 | bodyClassList.remove('highlight-code'); |
348 | if (this.controller_ && !window.opener) { | 392 | |
349 | var bodyClassList = document.body.classList; | 393 | // Toggle off speaker notes if they're showing when we move backwards on the |
394 | // main slides. If we're the speaker notes popup, leave them up. | ||
395 | if (this.controller_ && !this.IS_POPUP_) { | ||
396 | bodyClassList.remove('with-notes'); | ||
397 | } else if (!this.controller_) { | ||
350 | bodyClassList.remove('with-notes'); | 398 | bodyClassList.remove('with-notes'); |
351 | bodyClassList.remove('highlight-code'); | ||
352 | } | 399 | } |
353 | 400 | ||
354 | if (this.controller_) { | 401 | // if (this.controller_) { |
355 | this.controller_.sendMsg({slideDirection: SlideController.MOVE_LEFT}); | 402 | // this.controller_.sendMsg({slideDirection: SlideController.MOVE_LEFT}); |
356 | } | 403 | // } |
357 | 404 | ||
358 | this.prevSlide_ = this.curSlide_; | 405 | this.prevSlide_ = this.curSlide_; |
359 | this.curSlide_--; | 406 | this.curSlide_--; |
@@ -366,22 +413,25 @@ SlideDeck.prototype.prevSlide = function(opt_dontPush) { | |||
366 | * @param {boolean=} opt_dontPush | 413 | * @param {boolean=} opt_dontPush |
367 | */ | 414 | */ |
368 | SlideDeck.prototype.nextSlide = function(opt_dontPush) { | 415 | SlideDeck.prototype.nextSlide = function(opt_dontPush) { |
369 | 416 | // | |
370 | if (this.controller_) { | 417 | // if (this.controller_) { |
371 | this.controller_.sendMsg({slideDirection: SlideController.MOVE_RIGHT}); | 418 | // this.controller_.sendMsg({slideDirection: SlideController.MOVE_RIGHT}); |
372 | } | 419 | // } |
373 |