Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/RFinance2014/libraries/frameworks/io2012/js/slide-deck.js
1436 views
1
/**
2
* @authors Luke Mahe
3
* @authors Eric Bidelman
4
* @fileoverview TODO
5
*/
6
document.cancelFullScreen = document.webkitCancelFullScreen ||
7
document.mozCancelFullScreen;
8
9
/**
10
* @constructor
11
*/
12
function SlideDeck(el) {
13
this.curSlide_ = 0;
14
this.prevSlide_ = 0;
15
this.config_ = null;
16
this.container = el || document.querySelector('slides');
17
this.slides = [];
18
this.controller = null;
19
this.timings = [{slide: 1, time: new Date().getTime()}];
20
21
this.getCurrentSlideFromHash_();
22
23
// Call this explicitly. Modernizr.load won't be done until after DOM load.
24
this.onDomLoaded_.bind(this)();
25
26
// Trigger links from Table of Contents to Slides.
27
this.showContents();
28
}
29
30
/**
31
* @const
32
* @private
33
*/
34
SlideDeck.prototype.SLIDE_CLASSES_ = [
35
'far-past', 'past', 'current', 'next', 'far-next'];
36
37
/**
38
* @const
39
* @private
40
*/
41
SlideDeck.prototype.CSS_DIR_ = 'theme/css/';
42
43
/**
44
* @private
45
*/
46
SlideDeck.prototype.getCurrentSlideFromHash_ = function() {
47
var slideNo = parseInt(document.location.hash.substr(1));
48
49
if (slideNo) {
50
this.curSlide_ = slideNo - 1;
51
} else {
52
this.curSlide_ = 0;
53
}
54
};
55
56
/**
57
* @param {number} slideNo
58
*/
59
SlideDeck.prototype.loadSlide = function(slideNo) {
60
if (slideNo) {
61
this.curSlide_ = slideNo - 1;
62
this.updateSlides_();
63
}
64
};
65
66
/**
67
* @private
68
*/
69
SlideDeck.prototype.onDomLoaded_ = function(e) {
70
document.body.classList.add('loaded'); // Add loaded class for templates to use.
71
72
this.slides = this.container.querySelectorAll('slide:not([hidden]):not(.backdrop)');
73
74
// If we're on a smartphone, apply special sauce.
75
if (Modernizr.mq('only screen and (max-device-width: 480px)')) {
76
// var style = document.createElement('link');
77
// style.rel = 'stylesheet';
78
// style.type = 'text/css';
79
// style.href = this.CSS_DIR_ + 'phone.css';
80
// document.querySelector('head').appendChild(style);
81
82
// No need for widescreen layout on a phone.
83
this.container.classList.remove('layout-widescreen');
84
}
85
86
this.loadConfig_(SLIDE_CONFIG);
87
this.addEventListeners_();
88
this.updateSlides_();
89
90
// Add slide numbers and total slide count metadata to each slide.
91
var that = this;
92
for (var i = 0, slide; slide = this.slides[i]; ++i) {
93
slide.dataset.slideNum = i + 1;
94
slide.dataset.totalSlides = this.slides.length;
95
96
slide.addEventListener('click', function(e) {
97
if (document.body.classList.contains('overview')) {
98
that.loadSlide(this.dataset.slideNum);
99
e.preventDefault();
100
window.setTimeout(function() {
101
that.toggleOverview();
102
}, 500);
103
}
104
}, false);
105
}
106
107
// Note: this needs to come after addEventListeners_(), which adds a
108
// 'keydown' listener that this controller relies on.
109
// Also, no need to set this up if we're on mobile.
110
if (!Modernizr.touch) {
111
this.controller = new SlideController(this);
112
if (this.controller.isPopup) {
113
document.body.classList.add('popup');
114
}
115
}
116
};
117
118
/**
119
* @private
120
*/
121
SlideDeck.prototype.addEventListeners_ = function() {
122
document.addEventListener('keydown', this.onBodyKeyDown_.bind(this), false);
123
window.addEventListener('popstate', this.onPopState_.bind(this), false);
124
125
// var transEndEventNames = {
126
// 'WebkitTransition': 'webkitTransitionEnd',
127
// 'MozTransition': 'transitionend',
128
// 'OTransition': 'oTransitionEnd',
129
// 'msTransition': 'MSTransitionEnd',
130
// 'transition': 'transitionend'
131
// };
132
//
133
// // Find the correct transitionEnd vendor prefix.
134
// window.transEndEventName = transEndEventNames[
135
// Modernizr.prefixed('transition')];
136
//
137
// // When slides are done transitioning, kickoff loading iframes.
138
// // Note: we're only looking at a single transition (on the slide). This
139
// // doesn't include autobuilds the slides may have. Also, if the slide
140
// // transitions on multiple properties (e.g. not just 'all'), this doesn't
141
// // handle that case.
142
// this.container.addEventListener(transEndEventName, function(e) {
143
// this.enableSlideFrames_(this.curSlide_);
144
// }.bind(this), false);
145
146
// document.addEventListener('slideenter', function(e) {
147
// var slide = e.target;
148
// window.setTimeout(function() {
149
// this.enableSlideFrames_(e.slideNumber);
150
// this.enableSlideFrames_(e.slideNumber + 1);
151
// }.bind(this), 300);
152
// }.bind(this), false);
153
};
154
155
/**
156
* @private
157
* @param {Event} e The pop event.
158
*/
159
SlideDeck.prototype.onPopState_ = function(e) {
160
if (e.state != null) {
161
this.curSlide_ = e.state;
162
this.updateSlides_(true);
163
}
164
};
165
166
/**
167
* @param {Event} e
168
*/
169
SlideDeck.prototype.onBodyKeyDown_ = function(e) {
170
if (/^(input|textarea)$/i.test(e.target.nodeName) ||
171
e.target.isContentEditable) {
172
return;
173
}
174
175
// Forward keydowns to the main slides if we're the popup.
176
if (this.controller && this.controller.isPopup) {
177
this.controller.sendMsg({keyCode: e.keyCode});
178
}
179
180
switch (e.keyCode) {
181
case 13: // Enter
182
if (document.body.classList.contains('overview')) {
183
this.toggleOverview();
184
}
185
break;
186
187
case 39: // right arrow
188
case 32: // space
189
case 34: // PgDn
190
this.nextSlide();
191
this.recordTimings(false);
192
e.preventDefault();
193
break;
194
195
case 76: //l
196
this.recordTimings(true);
197
e.preventDefault();
198
break;
199
200
case 37: // left arrow
201
case 8: // Backspace
202
case 33: // PgUp
203
this.prevSlide();
204
e.preventDefault();
205
break;
206
207
case 40: // down arrow
208
this.nextSlide();
209
e.preventDefault();
210
break;
211
212
case 38: // up arrow
213
this.prevSlide();
214
e.preventDefault();
215
break;
216
217
// inserted to work with popcorn.js
218
case 71: // G: Go to slide
219
var slideNumber = prompt('Go to slide: ');
220
if (slideNumber != null) {
221
this.gotoSlide(parseInt(slideNumber) - 1);
222
}
223
break;
224
225
// inserted to display table of contents
226
case 84: // T: Toggle Table of Contents
227
$("#io2012-ptoc").toggle();
228
// $("div#io2012-toc li.dropdown").toggleClass("open");
229
// document.body.classList.toggle('show-comments')
230
break;
231
232
case 72: // H: Toggle code highlighting
233
document.body.classList.toggle('highlight-code');
234
break;
235
236
case 79: // O: Toggle overview
237
this.toggleOverview();
238
break;
239
240
case 80: // P
241
if (this.controller && this.controller.isPopup) {
242
document.body.classList.toggle('with-notes');
243
} else if (this.controller && !this.controller.popup) {
244
document.body.classList.toggle('with-notes');
245
}
246
break;
247
248
case 82: // R
249
// TODO: implement refresh on main slides when popup is refreshed.
250
break;
251
252
case 27: // ESC: Hide notes and highlighting
253
document.body.classList.remove('with-notes');
254
document.body.classList.remove('highlight-code');
255
256
if (document.body.classList.contains('overview')) {
257
this.toggleOverview();
258
}
259
break;
260
261
case 70: // F: Toggle fullscreen
262
// Only respect 'f' on body. Don't want to capture keys from an <input>.
263
// Also, ignore browser's fullscreen shortcut (cmd+shift+f) so we don't
264
// get trapped in fullscreen!
265
if (e.target == document.body && !(e.shiftKey && e.metaKey)) {
266
if (document.mozFullScreen !== undefined && !document.mozFullScreen) {
267
document.body.mozRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
268
} else if (document.webkitIsFullScreen !== undefined && !document.webkitIsFullScreen) {
269
document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
270
} else {
271
document.cancelFullScreen();
272
}
273
}
274
break;
275
276
case 87: // W: Toggle widescreen
277
// Only respect 'w' on body. Don't want to capture keys from an <input>.
278
if (e.target == document.body && !(e.shiftKey && e.metaKey)) {
279
this.container.classList.toggle('layout-widescreen');
280
}
281
break;
282
}
283
};
284
285
/**
286
*
287
*/
288
SlideDeck.prototype.focusOverview_ = function() {
289
var overview = document.body.classList.contains('overview');
290
291
for (var i = 0, slide; slide = this.slides[i]; i++) {
292
slide.style[Modernizr.prefixed('transform')] = overview ?
293
'translateZ(-2500px) translate(' + (( i - this.curSlide_ ) * 105) +
294
'%, 0%)' : '';
295
}
296
};
297
298
/**
299
*/
300
SlideDeck.prototype.toggleOverview = function() {
301
document.body.classList.toggle('overview');
302
303
this.focusOverview_();
304
};
305
306
/**
307
* @private
308
*/
309
SlideDeck.prototype.loadConfig_ = function(config) {
310
if (!config) {
311
return;
312
}
313
314
this.config_ = config;
315
316
var settings = this.config_.settings;
317
318
this.loadTheme_(settings.theme || []);
319
320
/*
321
if (settings.favIcon) {
322
this.addFavIcon_(settings.favIcon);
323
}
324
*/
325
326
// Prettyprint. Default to on.
327
if (!!!('usePrettify' in settings) || settings.usePrettify) {
328
prettyPrint();
329
}
330
331
if (settings.analytics) {
332
this.loadAnalytics_();
333
}
334
335
if (settings.fonts) {
336
this.addFonts_(settings.fonts);
337
}
338
339
// Builds. Default to on.
340
if (!!!('useBuilds' in settings) || settings.useBuilds) {
341
this.makeBuildLists_();
342
}
343
344
if (settings.title) {
345
document.title = settings.title.replace(/<br\/?>/, ' ') + ' - Google IO 2012';
346
document.querySelector('[data-config-title]').innerHTML = settings.title;
347
}
348
349
if (settings.subtitle) {
350
document.querySelector('[data-config-subtitle]').innerHTML = settings.subtitle;
351
}
352
353
if (this.config_.presenters) {
354
var presenters = this.config_.presenters;
355
var dataConfigContact = document.querySelector('[data-config-contact]');
356
357
var html = [];
358
if (presenters.length == 1) {
359
var p = presenters[0];
360
361
html = [p.name, p.company].join('<br>');
362
363
var gplus = p.gplus ? '<span>g+</span><a href="' + p.gplus +
364
'">' + p.gplus.replace(/https?:\/\//, '') + '</a>' : '';
365
366
var twitter = p.twitter ? '<span>twitter</span>' +
367
'<a href="http://twitter.com/' + p.twitter + '">' +
368
p.twitter + '</a>' : '';
369
370
var www = p.www ? '<span>www</span><a href="' + p.www +
371
'">' + p.www.replace(/https?:\/\//, '') + '</a>' : '';
372
373
var github = p.github ? '<span>github</span><a href="' + p.github +
374
'">' + p.github.replace(/https?:\/\//, '') + '</a>' : '';
375
376
var html2 = [gplus, twitter, www, github].join('<br>');
377
378
if (dataConfigContact) {
379
dataConfigContact.innerHTML = html2;
380
}
381
} else {
382
for (var i = 0, p; p = presenters[i]; ++i) {
383
html.push(p.name + ' - ' + p.company);
384
}
385
html = html.join('<br>');
386
if (dataConfigContact) {
387
dataConfigContact.innerHTML = html;
388
}
389
}
390
391
var dataConfigPresenter = document.querySelector('[data-config-presenter]');
392
if (dataConfigPresenter) {
393
document.querySelector('[data-config-presenter]').innerHTML = html;
394
}
395
}
396
397
/* Left/Right tap areas. Default to including. */
398
if (!!!('enableSlideAreas' in settings) || settings.enableSlideAreas) {
399
var el = document.createElement('div');
400
el.classList.add('slide-area');
401
el.id = 'prev-slide-area';
402
el.addEventListener('click', this.prevSlide.bind(this), false);
403
this.container.appendChild(el);
404
405
var el = document.createElement('div');
406
el.classList.add('slide-area');
407
el.id = 'next-slide-area';
408
el.addEventListener('click', this.nextSlide.bind(this), false);
409
this.container.appendChild(el);
410
}
411
412
if (Modernizr.touch && (!!!('enableTouch' in settings) ||
413
settings.enableTouch)) {
414
var self = this;
415
416
// Note: this prevents mobile zoom in/out but prevents iOS from doing
417
// it's crazy scroll over effect and disaligning the slides.
418
window.addEventListener('touchstart', function(e) {
419
e.preventDefault();
420
}, false);
421
422
var hammer = new Hammer(this.container);
423
hammer.ondragend = function(e) {
424
if (e.direction == 'right' || e.direction == 'down') {
425
self.prevSlide();
426
} else if (e.direction == 'left' || e.direction == 'up') {
427
self.nextSlide();
428
}
429
};
430
}
431
};
432
433
/**
434
* @private
435
* @param {Array.<string>} fonts
436
*/
437
SlideDeck.prototype.addFonts_ = function(fonts) {
438
var el = document.createElement('link');
439
el.rel = 'stylesheet';
440
el.href = ('https:' == document.location.protocol ? 'https' : 'http') +
441
'://fonts.googleapis.com/css?family=' + fonts.join('|') + '&v2';
442
document.querySelector('head').appendChild(el);
443
};
444
445
/**
446
* @private
447
*/
448
SlideDeck.prototype.buildNextItem_ = function() {
449
var slide = this.slides[this.curSlide_];
450
var toBuild = slide.querySelector('.to-build');
451
var built = slide.querySelector('.build-current');
452
453
if (built) {
454
built.classList.remove('build-current');
455
if (built.classList.contains('fade')) {
456
built.classList.add('build-fade');
457
}
458
}
459
460
if (!toBuild) {
461
var items = slide.querySelectorAll('.build-fade');
462
for (var j = 0, item; item = items[j]; j++) {
463
item.classList.remove('build-fade');
464
}
465
return false;
466
}
467
468
toBuild.classList.remove('to-build');
469
toBuild.classList.add('build-current');
470
471
return true;
472
};
473
474
/**
475
* @param {boolean=} opt_dontPush
476
*/
477
SlideDeck.prototype.prevSlide = function(opt_dontPush) {
478
if (this.curSlide_ > 0) {
479
var bodyClassList = document.body.classList;
480
bodyClassList.remove('highlight-code');
481
482
// Toggle off speaker notes if they're showing when we move backwards on the
483
// main slides. If we're the speaker notes popup, leave them up.
484
if (this.controller && !this.controller.isPopup) {
485
bodyClassList.remove('with-notes');
486
} else if (!this.controller) {
487
bodyClassList.remove('with-notes');
488
}
489
490
this.prevSlide_ = this.curSlide_--;
491
492
this.updateSlides_(opt_dontPush);
493
}
494
};
495
496
/**
497
* @param {boolean=} opt_dontPush
498
*/
499
SlideDeck.prototype.nextSlide = function(opt_dontPush) {
500
if (!document.body.classList.contains('overview') && this.buildNextItem_()) {
501
return;
502
}
503
504
if (this.curSlide_ < this.slides.length - 1) {
505
var bodyClassList = document.body.classList;
506
bodyClassList.remove('highlight-code');
507
508
// Toggle off speaker notes if they're showing when we advanced on the main
509
// slides. If we're the speaker notes popup, leave them up.
510
if (this.controller && !this.controller.isPopup) {
511
bodyClassList.remove('with-notes');
512
} else if (!this.controller) {
513
bodyClassList.remove('with-notes');
514
}
515
516
this.prevSlide_ = this.curSlide_++;
517
518
this.updateSlides_(opt_dontPush);
519
}
520
};
521
522
523
/* Slide events */
524
525
/**
526
* Triggered when a slide enter/leave event should be dispatched.
527
*
528
* @param {string} type The type of event to trigger
529
* (e.g. 'slideenter', 'slideleave').
530
* @param {number} slideNo The index of the slide that is being left.
531
*/
532
SlideDeck.prototype.triggerSlideEvent = function(type, slideNo) {
533
var el = this.getSlideEl_(slideNo);
534
if (!el) {
535
return;
536
}
537
538
// Call onslideenter/onslideleave if the attribute is defined on this slide.
539
var func = el.getAttribute(type);
540
if (func) {
541
new Function(func).call(el); // TODO: Don't use new Function() :(
542
}
543
544
// Dispatch event to listeners setup using addEventListener.
545
var evt = document.createEvent('Event');
546
evt.initEvent(type, true, true);
547
evt.slideNumber = slideNo + 1; // Make it readable
548
evt.slide = el;
549
550
el.dispatchEvent(evt);
551
};
552
553
554
// Inserted to work with popcorn.js
555
SlideDeck.prototype.gotoSlide = function(curSlide) {
556
if (curSlide < 0) {
557
curSlide = 0;
558
}
559
if (curSlide >= this.slides.length) {
560
curSlide = this.slides.length - 1;
561
}
562
this.curSlide_ = curSlide;
563
this.prevSlide_ = curSlide - 1;
564
this.updateSlides_();
565
};
566
567
// Record event timings to synchronize with popcorn.js
568
// TODO: Make it more general so that events of different types can be captured.
569
// For example, it would be useful to capture when p is pressed so that it can
570
// be simulated while syncing with the video.
571
SlideDeck.prototype.recordTimings = function(pause){
572
var temp = {
573
"time": new Date().getTime() - this.timings[0].time,
574
"slide": this.curSlide_ + 1
575
};
576
if (pause === true){
577
temp.action = 'pause'
578
} else if (temp.slide === this.timings[this.timings.length - 1].slide){
579
temp.action = "nextSlide"
580
} else {
581
temp.action = "gotoSlide"
582
};
583
this.timings.push(temp);
584
console.log(JSON.stringify(this.timings));
585
};
586
587
SlideDeck.prototype.showContents = function(){
588
var self = this;
589
$('ul.dropdown-menu li a').live('click', function(){
590
var i = $(this).data('slide');
591
self.gotoSlide(i+1);
592
});
593
};
594
595
SlideDeck.prototype.highlightCurSlide = function(){
596
self = this;
597
var _i = this.curSlide_ - 2;
598
$('ul.dropdown-menu li').removeClass('current');
599
$('ul.dropdown-menu li:eq(' + _i + ')').addClass('current');
600
$('div.pagination li').removeClass('active');
601
$('div.pagination li:eq(' + _i + ')').addClass('active');
602
$('div.pagination li a').live('click', function(){
603
var i = $(this).data('slide');
604
self.gotoSlide(i + 1);
605
});
606
};
607
608
/**
609
* @private
610
*/
611
SlideDeck.prototype.updateSlides_ = function(opt_dontPush) {
612
var dontPush = opt_dontPush || false;
613
614
var curSlide = this.curSlide_;
615
for (var i = 0; i < this.slides.length; ++i) {
616
switch (i) {
617
case curSlide - 2:
618
this.updateSlideClass_(i, 'far-past');
619
break;
620
case curSlide - 1:
621
this.updateSlideClass_(i, 'past');
622
break;
623
case curSlide:
624
this.updateSlideClass_(i, 'current');
625
break;
626
case curSlide + 1:
627
this.updateSlideClass_(i, 'next');
628
break;
629
case curSlide + 2:
630
this.updateSlideClass_(i, 'far-next');
631
break;
632
default:
633
this.updateSlideClass_(i);
634
break;
635
}
636
};
637
638
this.triggerSlideEvent('slideleave', this.prevSlide_);
639
this.triggerSlideEvent('slideenter', curSlide);
640
641
// window.setTimeout(this.disableSlideFrames_.bind(this, curSlide - 2), 301);
642
//
643
// this.enableSlideFrames_(curSlide - 1); // Previous slide.
644
// this.enableSlideFrames_(curSlide + 1); // Current slide.
645
// this.enableSlideFrames_(curSlide + 2); // Next slide.
646
647
// Enable current slide's iframes (needed for page loat at current slide).
648
this.enableSlideFrames_(curSlide + 1);
649
650
// No way to tell when all slide transitions + auto builds are done.
651
// Give ourselves a good buffer to preload the next slide's iframes.
652
window.setTimeout(this.enableSlideFrames_.bind(this, curSlide + 2), 1000);
653
654
this.updateHash_(dontPush);
655
656
if (document.body.classList.contains('overview')) {
657
this.focusOverview_();
658
return;
659
}
660
661
// highlight current slide in table of contents
662
this.highlightCurSlide();
663
};
664
665
/**
666
* @private
667
* @param {number} slideNo
668
*/
669
SlideDeck.prototype.enableSlideFrames_ = function(slideNo) {
670
var el = this.slides[slideNo - 1];
671
if (!el) {
672
return;
673
}
674
675
var frames = el.querySelectorAll('iframe');
676
for (var i = 0, frame; frame = frames[i]; i++) {
677
this.enableFrame_(frame);
678
}
679
};
680
681
/**
682
* @private
683
* @param {number} slideNo
684
*/
685
SlideDeck.prototype.enableFrame_ = function(frame) {
686
var src = frame.dataset.src;
687
if (src && frame.src != src) {
688
frame.src = src;
689
}
690
};
691
692
/**
693
* @private
694
* @param {number} slideNo
695
*/
696
SlideDeck.prototype.disableSlideFrames_ = function(slideNo) {
697
var el = this.slides[slideNo - 1];
698
if (!el) {
699
return;
700
}
701
702
var frames = el.querySelectorAll('iframe');
703
for (var i = 0, frame; frame = frames[i]; i++) {
704
this.disableFrame_(frame);
705
}
706
};
707
708
/**
709
* @private
710
* @param {Node} frame
711
*/
712
SlideDeck.prototype.disableFrame_ = function(frame) {
713
frame.src = 'about:blank';
714
};
715
716
/**
717
* @private
718
* @param {number} slideNo
719
*/
720
SlideDeck.prototype.getSlideEl_ = function(no) {
721
if ((no < 0) || (no >= this.slides.length)) {
722
return null;
723
} else {
724
return this.slides[no];
725
}
726
};
727
728
/**
729
* @private
730
* @param {number} slideNo
731
* @param {string} className
732
*/
733
SlideDeck.prototype.updateSlideClass_ = function(slideNo, className) {
734
var el = this.getSlideEl_(slideNo);
735
736
if (!el) {
737
return;
738
}
739
740
if (className) {
741
el.classList.add(className);
742
}
743
744
for (var i = 0, slideClass; slideClass = this.SLIDE_CLASSES_[i]; ++i) {
745
if (className != slideClass) {
746
el.classList.remove(slideClass);
747
}
748
}
749
};
750
751
/**
752
* @private
753
*/
754
SlideDeck.prototype.makeBuildLists_ = function () {
755
for (var i = this.curSlide_, slide; slide = this.slides[i]; ++i) {
756
var items = slide.querySelectorAll('.build > *');
757
for (var j = 0, item; item = items[j]; ++j) {
758
if (item.classList) {
759
item.classList.add('to-build');
760
if (item.parentNode.classList.contains('fade')) {
761
item.classList.add('fade');
762
}
763
}
764
}
765
}
766
};
767
768
/**
769
* @private
770
* @param {boolean} dontPush
771
*/
772
SlideDeck.prototype.updateHash_ = function(dontPush) {
773
if (!dontPush) {
774
var slideNo = this.curSlide_ + 1;
775
var hash = '#' + slideNo;
776
if (window.history.pushState) {
777
window.history.pushState(this.curSlide_, 'Slide ' + slideNo, hash);
778
} else {
779
window.location.replace(hash);
780
}
781
782
// Record GA hit on this slide.
783
window['_gaq'] && window['_gaq'].push(['_trackPageview',
784
document.location.href]);
785
}
786
};
787
788
789
/**
790
* @private
791
* @param {string} favIcon
792
*/
793
SlideDeck.prototype.addFavIcon_ = function(favIcon) {
794
var el = document.createElement('link');
795
el.rel = 'icon';
796
el.type = 'image/png';
797
el.href = favIcon;
798
document.querySelector('head').appendChild(el);
799
};
800
801
/**
802
* @private
803
* @param {string} theme
804
*/
805
SlideDeck.prototype.loadTheme_ = function(theme) {
806
var styles = [];
807
if (theme.constructor.name === 'String') {
808
styles.push(theme);
809
} else {
810
styles = theme;
811
}
812
813
for (var i = 0, style; themeUrl = styles[i]; i++) {
814
var style = document.createElement('link');
815
style.rel = 'stylesheet';
816
style.type = 'text/css';
817
if (themeUrl.indexOf('http') == -1) {
818
style.href = this.CSS_DIR_ + themeUrl + '.css';
819
} else {
820
style.href = themeUrl;
821
}
822
document.querySelector('head').appendChild(style);
823
}
824
};
825
826
/**
827
* @private
828
*/
829
SlideDeck.prototype.loadAnalytics_ = function() {
830
var _gaq = window['_gaq'] || [];
831
_gaq.push(['_setAccount', this.config_.settings.analytics]);
832
_gaq.push(['_trackPageview']);
833
834
(function() {
835
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
836
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
837
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
838
})();
839
};
840
841
842
// Polyfill missing APIs (if we need to), then create the slide deck.
843
// iOS < 5 needs classList, dataset, and window.matchMedia. Modernizr contains
844
// the last one.
845
(function() {
846
Modernizr.load({
847
test: !!document.body.classList && !!document.body.dataset,
848
nope: ['js/polyfills/classList.min.js', 'js/polyfills/dataset.min.js'],
849
complete: function() {
850
window.slidedeck = new SlideDeck();
851
}
852
});
853
})();
854
855