slide-em-up 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -0,0 +1,35 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
6
+ <title><%= meta.title %></title>
7
+ <% (theme.css + meta.css).each do |css| %>
8
+ <link rel="stylesheet" href="<%= css%>">
9
+ <% end %>
10
+ <link rel="stylesheet" href="css/pygments/native.css">
11
+ </head>
12
+ <body data-duration="60">
13
+ <section>
14
+ <header class="slide">
15
+ <h1><%= meta.title %></h1>
16
+ </header>
17
+ </section>
18
+ <% sections.each do |section| %>
19
+ <section>
20
+ <header class="slide">
21
+ <h1><%= section.title %></h1>
22
+ </header>
23
+ <% section.slides.each do |slide| %>
24
+ <section class="slide <%= slide.classes %>">
25
+ <%= slide.html %>
26
+ </section>
27
+ <% end %>
28
+ </section>
29
+ <% end %>
30
+ <% (theme.js + meta.js).each do |js| %>
31
+ <script src="<%= js %>"></script>
32
+ <% end %>
33
+ <script>var slideshow = new SlideShow();</script>
34
+ </body>
35
+ </html>
@@ -0,0 +1,116 @@
1
+ /*
2
+ * classList.js: Implements a cross-browser element.classList getter.
3
+ * 2010-09-06
4
+ *
5
+ * By Eli Grey, http://eligrey.com
6
+ * Public Domain.
7
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8
+ */
9
+
10
+ "use strict";
11
+
12
+ if (typeof Element !== "undefined") {
13
+
14
+ (function () {
15
+
16
+ var
17
+ classListProp = "classList"
18
+ , protoProp = "prototype"
19
+ , elemCtrProto = Element[protoProp]
20
+ , objCtr = Object
21
+ ;
22
+ if (!objCtr.hasOwnProperty.call(elemCtrProto, classListProp)) {
23
+ var
24
+ strTrim = String[protoProp].trim || function () {
25
+ return this.replace(/^\s+|\s+$/g, "");
26
+ }
27
+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
28
+ for (var i = 0, len = this.length; i < len; i++) {
29
+ if (i in this && this[i] === item) {
30
+ return i;
31
+ }
32
+ }
33
+ return -1;
34
+ }
35
+ , checkTokenAndGetIndex = function (classList, token) {
36
+ if (token === "") {
37
+ throw "SYNTAX_ERR";
38
+ }
39
+ if (/\s/.test(token)) {
40
+ throw "INVALID_CHARACTER_ERR";
41
+ }
42
+ return arrIndexOf.call(classList, token);
43
+ }
44
+ , ClassList = function (elem) {
45
+ var
46
+ trimmedClasses = strTrim.call(elem.className)
47
+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
48
+ ;
49
+ for (var i = 0, len = classes.length; i < len; i++) {
50
+ this.push(classes[i]);
51
+ }
52
+ this.updateClassName = function () {
53
+ elem.className = this.toString();
54
+ };
55
+ }
56
+ , classListProto = ClassList[protoProp] = []
57
+ , classListGetter = function () {
58
+ return new ClassList(this);
59
+ }
60
+ ;
61
+ classListProto.item = function (i) {
62
+ return this[i] || null;
63
+ };
64
+ classListProto.contains = function (token) {
65
+ token += "";
66
+ return checkTokenAndGetIndex(this, token) !== -1;
67
+ };
68
+ classListProto.add = function (token) {
69
+ token += "";
70
+ if (checkTokenAndGetIndex(this, token) === -1) {
71
+ this.push(token);
72
+ this.updateClassName();
73
+ }
74
+ };
75
+ classListProto.remove = function (token) {
76
+ token += "";
77
+ var index = checkTokenAndGetIndex(this, token);
78
+ if (index !== -1) {
79
+ this.splice(index, 1);
80
+ this.updateClassName();
81
+ }
82
+ };
83
+ classListProto.toggle = function (token) {
84
+ token += "";
85
+ if (checkTokenAndGetIndex(this, token) === -1) {
86
+ this.add(token);
87
+ } else {
88
+ this.remove(token);
89
+ }
90
+ };
91
+ classListProto.toString = function () {
92
+ return this.join(" ");
93
+ };
94
+
95
+ if (objCtr.defineProperty) {
96
+ var classListDescriptor = {
97
+ get: classListGetter
98
+ , enumerable: true
99
+ , configurable: true
100
+ };
101
+ try {
102
+ objCtr.defineProperty(elemCtrProto, classListProp, classListDescriptor);
103
+ } catch (ex) { // IE 8 doesn't support enumerable:true
104
+ if (ex.number === -0x7FF5EC54) {
105
+ classListDescriptor.enumerable = false;
106
+ objCtr.defineProperty(elemCtrProto, classListProp, classListDescriptor);
107
+ }
108
+ }
109
+ } else if (objCtr[protoProp].__defineGetter__) {
110
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
111
+ }
112
+ }
113
+
114
+ }());
115
+
116
+ }
@@ -0,0 +1,483 @@
1
+ /**
2
+ * CSSS javascript code
3
+ * @author Lea Verou (http://leaverou.me)
4
+ * @version 2.0
5
+ */
6
+
7
+ /**
8
+ * Make the environment a bit friendlier
9
+ */
10
+ function $(expr, con) { if(con && !con.querySelector) console.trace();
11
+ return (con || document).querySelector(expr); }
12
+ function $$(expr, con) { return [].slice.call((con || document).querySelectorAll(expr)); }
13
+
14
+ (function(head, body){
15
+
16
+ // Check for classList support and include the polyfill if it's not supported
17
+ if(!('classList' in body)) {
18
+ var thisScript = $('script[src$="slideshow.js"]'),
19
+ script = document.createElement('script');
20
+ script.src = thisScript.src.replace(/\bslideshow\.js/, 'classList.js');
21
+ thisScript.parentNode.insertBefore(script, thisScript);
22
+ }
23
+
24
+ // Cache <title> element, we may need it for slides that don't have titles
25
+ var documentTitle = document.title + '';
26
+
27
+ var self = window.SlideShow = function(container, slide) {
28
+ var me = this;
29
+
30
+ // Set instance
31
+ if(!window.slideshow) {
32
+ window.slideshow = this;
33
+ }
34
+
35
+ container = container || body;
36
+
37
+ // Current slide
38
+ this.slide = slide || 0;
39
+
40
+ // Current .delayed item in the slide
41
+ this.item = 0;
42
+
43
+ // Do we need to add a timer?
44
+ this.duration = container.getAttribute('data-duration');
45
+
46
+ if(this.duration > 0) {
47
+ var timer = document.createElement('div'),
48
+ declaration = 'transition: ' + this.duration * 60 + 's linear; ';
49
+
50
+ timer.id = 'timer';
51
+ timer.setAttribute('style', '-moz-' + declaration + '-webkit-' + declaration + '-o-' + declaration + '-ms-' + declaration + declaration);
52
+ container.appendChild(timer);
53
+
54
+ setTimeout(function() {
55
+ timer.className = 'end';
56
+ }, 1);
57
+ }
58
+
59
+ var delayed = $$('ol li', container);
60
+ for (var i=0; i<delayed.length; i++) {
61
+ delayed[i].className = "delayed";
62
+ }
63
+
64
+ // Get the slide elements into an array
65
+ this.slides = Array.prototype.slice.apply($$('.slide', container));
66
+
67
+ for(var i=0; i<this.slides.length; i++) {
68
+ var slide = this.slides[i]; // to speed up references
69
+
70
+ // Asign ids to slides that don't have one
71
+ if(!slide.id) {
72
+ slide.id = 'slide' + (i+1);
73
+ }
74
+
75
+ // Set data-title attribute to the title of the slide
76
+ if(!slide.title) {
77
+ // no title attribute, fetch title from heading(s)
78
+ var heading = $('hgroup', slide) || $('h1,h2,h3,h4,h5,h6', slide);
79
+
80
+ if(heading && heading.textContent.trim()) {
81
+ slide.setAttribute('data-title', heading.textContent);
82
+ }
83
+ }
84
+ else {
85
+ // The title attribute is set, use that
86
+ slide.setAttribute('data-title', slide.title);
87
+ slide.removeAttribute('title');
88
+ }
89
+ }
90
+
91
+ // If there's already a hash, update current slide number...
92
+ this.goto(location.hash.substr(1) || 0);
93
+
94
+ // ...and keep doing so every time the hash changes
95
+ this.onhashchange = function() {
96
+ me.goto(location.hash.substr(1) || 0);
97
+ };
98
+ window.addEventListener('hashchange', this.onhashchange, false);
99
+
100
+ if(window.name === 'projector') {
101
+ document.body.classList.add('projector');
102
+ }
103
+
104
+ // Adjust the font-size when the window is resized
105
+ addEventListener('resize', function() {
106
+ me.adjustFontSize();
107
+ }, false);
108
+
109
+ // In some browsers DOMContentLoaded is too early, so try again onload
110
+ addEventListener('load', function() {
111
+ me.adjustFontSize();
112
+ }, false);
113
+
114
+ /**
115
+ Keyboard navigation
116
+ Ctrl+G : Go to slide...
117
+ Ctrl+H : Show thumbnails and go to slide
118
+ Ctrl+P : Presenter view
119
+ (Shift instead of Ctrl works too)
120
+ */
121
+ document.addEventListener('keyup', function(evt) {
122
+ if(evt.ctrlKey || evt.shiftKey) {
123
+ switch(evt.keyCode) {
124
+ case 71: // G
125
+ var slide = prompt('Which slide?');
126
+ me.goto(+slide? slide - 1 : slide);
127
+ break;
128
+ case 72: // H
129
+ if(body.classList.contains('show-thumbnails')) {
130
+ body.classList.remove('show-thumbnails');
131
+ body.classList.remove('headers-only');
132
+ }
133
+ else {
134
+ body.classList.add('show-thumbnails');
135
+
136
+ if(!evt.shiftKey || !evt.ctrlKey) {
137
+ body.classList.add('headers-only');
138
+ }
139
+
140
+ body.addEventListener('click', function(evt) {
141
+ var slide = evt.target;
142
+
143
+ while(slide && !slide.classList.contains('slide')) {
144
+ slide = slide.parentNode;
145
+ }
146
+
147
+ if(slide) {
148
+ me.goto(slide.id);
149
+ setTimeout(function() { me.adjustFontSize(); }, 1000); // for Opera
150
+ }
151
+
152
+ body.classList.remove('show-thumbnails');
153
+ body.classList.remove('headers-only');
154
+ }, false);
155
+ }
156
+ break;
157
+ case 74: // J
158
+ if(body.classList.contains('hide-elements')) {
159
+ body.classList.remove('hide-elements');
160
+ }
161
+ else {
162
+ body.classList.add('hide-elements');
163
+ }
164
+ break;
165
+ case 80: // P
166
+ // Open new window for attendee view
167
+ me.projector = open(location, 'projector');
168
+
169
+ // Get the focus back
170
+ window.focus();
171
+
172
+ // Switch this one to presenter view
173
+ body.classList.add('presenter');
174
+ }
175
+ }
176
+ }, false);
177
+
178
+ /**
179
+ Keyboard navigation
180
+ Home : First slide
181
+ End : Last slide
182
+ Space/Up/Right arrow : Next item/slide
183
+ Ctrl + Space/Up/Right arrow : Next slide
184
+ Down/Left arrow : Previous item/slide
185
+ Ctrl + Down/Left arrow : Previous slide
186
+ (Shift instead of Ctrl works too)
187
+ */
188
+ document.addEventListener('keydown', function(evt) {
189
+ if(evt.target === body || evt.target === body.parentNode || evt.altKey) {
190
+ if(evt.keyCode >= 32 && evt.keyCode <= 40) {
191
+ evt.preventDefault();
192
+ }
193
+
194
+ switch(evt.keyCode) {
195
+ case 33: //page up
196
+ me.previous();
197
+ break;
198
+ case 34: //page down
199
+ me.next();
200
+ break;
201
+ case 35: // end
202
+ me.end();
203
+ break;
204
+ case 36: // home
205
+ me.start();
206
+ break;
207
+ case 37: // <-
208
+ case 38: // up arrow
209
+ me.previous(evt.ctrlKey || evt.shiftKey);
210
+ break;
211
+ case 32: // space
212
+ case 39: // ->
213
+ case 40: // down arrow
214
+ me.next(evt.ctrlKey || evt.shiftKey);
215
+ break;
216
+ }
217
+ }
218
+ }, false);
219
+
220
+ if (window['EventSource'] != undefined) {
221
+ var source = new EventSource('/remote/sub/events');
222
+ source.onmessage = function(e) {
223
+ switch(e.data){
224
+ case 'next':
225
+ me.next();
226
+ break;
227
+ case 'prev':
228
+ me.prev();
229
+ break;
230
+ case 'up':
231
+ me.next(true);
232
+ break;
233
+ case 'down':
234
+ me.prev(true);
235
+ break;
236
+ default:
237
+ console.log(e);
238
+ };
239
+ };
240
+ }
241
+
242
+ // Rudimentary style[scoped] polyfill
243
+ var scoped = $$('style[scoped]', container);
244
+
245
+ for(var i=scoped.length; i--;) {
246
+ var style = scoped[i],
247
+ rulez = style.sheet.cssRules,
248
+ parentid = style.parentNode.id || self.getSlide(style).id;
249
+
250
+ for(var j=rulez.length; j--;) {
251
+ var cssText = rulez[j].cssText.replace(/^|,/g, function($0) { return '#' + parentid + ' ' + $0 });
252
+
253
+ style.sheet.deleteRule(0);
254
+ style.sheet.insertRule(cssText, 0);
255
+ }
256
+ }
257
+ }
258
+
259
+ self.prototype = {
260
+ start: function() {
261
+ this.goto(0);
262
+ },
263
+
264
+ end: function() {
265
+ this.goto(this.slides.length - 1);
266
+ },
267
+
268
+ /**
269
+ @param hard {Boolean} Whether to advance to the next slide (true) or
270
+ just the next step (which could very well be showing a list item)
271
+ */
272
+ next: function(hard) {
273
+ if(!hard && this.items.length) {
274
+ // If there's no current, then just mark the first one as such
275
+ if(!this.item) {
276
+ this.items[this.item++].classList.add('current');
277
+ }
278
+ // Add .current to current item if it exists, otherwise advance to next slide
279
+ else if(this.item < this.items.length) {
280
+ classes = this.items[this.item - 1].classList; // to speed up lookups
281
+
282
+ classes.remove('current');
283
+ classes.add('displayed');
284
+
285
+ this.items[this.item++].classList.add('current');
286
+ }
287
+ else {
288
+ this.item = 0;
289
+ this.next(true);
290
+ }
291
+ }
292
+ else {
293
+ this.goto(this.slide + 1);
294
+
295
+ this.item = 0;
296
+
297
+ // Mark all items as not displayed, if there are any
298
+ if(this.items.length) {
299
+ for (var i=0; i<this.items.length; i++) {
300
+ if(this.items[i].classList) {
301
+ this.items[i].classList.remove('displayed');
302
+ this.items[i].classList.remove('current');
303
+ }
304
+ }
305
+ }
306
+ }
307
+ },
308
+
309
+ previous: function(hard) {
310
+ if(!hard && this.item > 0) {
311
+ var classes = this.items[this.item - 1].classList; // to speed up lookups
312
+
313
+ classes.remove('current');
314
+
315
+ if(this.item > 1) {
316
+ classes = this.items[--this.item - 1].classList;
317
+
318
+ classes.remove('displayed');
319
+ classes.add('current');
320
+ }
321
+ else {
322
+ this.item = 0;
323
+ }
324
+ }
325
+ else {
326
+
327
+ this.goto(this.slide - 1);
328
+
329
+ this.item = this.items.length;
330
+
331
+ // Mark all items as displayed, if there are any
332
+ if(this.items.length) {
333
+ for (var i=0; i<this.items.length; i++) {
334
+ if(this.items[i].classList) {
335
+ this.items[i].classList.add('displayed');
336
+ }
337
+ }
338
+
339
+ // Mark the last one as current
340
+ var lastItem = this.items[this.items.length - 1];
341
+
342
+ lastItem.classList.remove('displayed');
343
+ lastItem.classList.add('current');
344
+ }
345
+ }
346
+ },
347
+
348
+ /**
349
+ Go to an aribtary slide
350
+ @param which {String|Integer} Which slide (identifier or slide number)
351
+ */
352
+ goto: function(which) {
353
+ var slide;
354
+
355
+ // We have to remove it to prevent multiple calls to goto messing up
356
+ // our current item (and there's no point either, so we save on performance)
357
+ window.removeEventListener('hashchange', this.onhashchange, false);
358
+
359
+ if(which + 0 === which && which in this.slides) { // Argument is a valid slide number
360
+ this.slide = which;
361
+
362
+ slide = this.slides[this.slide];
363
+ location.hash = '#' + slide.id;
364
+ }
365
+ else if(which + '' === which) { // Argument is a slide id
366
+ slide = document.getElementById(which);
367
+
368
+ if(slide) {
369
+ this.slide = this.slides.indexOf(slide);
370
+ location.hash = '#' + which;
371
+ }
372
+ }
373
+
374
+ if(slide) { // Slide actually changed, perform any other tasks needed
375
+ document.title = slide.getAttribute('data-title') || documentTitle;
376
+
377
+ this.adjustFontSize();
378
+
379
+ // Update items collection
380
+ this.items = $$('.delayed, .delayed-children > *', this.slides[this.slide]);
381
+ this.item = 0;
382
+
383
+ // Tell other windows
384
+ if(this.projector && this.projector.slideshow && this.projector.slideshow.slide != this.slide) {
385
+ this.projector.slideshow.goto(this.slide);
386
+ }
387
+
388
+ if(window.opener && opener.slideshow && opener.slideshow.slide != this.slide) {
389
+ opener.slideshow.goto(this.slide);
390
+ }
391
+
392
+ // Update next/previous
393
+ for (var i=this.slides.length; i--;) {
394
+ this.slides[i].classList.remove('previous');
395
+ this.slides[i].classList.remove('next');
396
+ }
397
+
398
+ this.slides.previous = this.slides[this.slide-1];
399
+ this.slides.next = this.slides[this.slide+1];
400
+
401
+ this.slides.previous && this.slides.previous.classList.add('previous');
402
+ this.slides.next && this.slides.next.classList.add('next');
403
+ }
404
+
405
+ // If you attach the listener immediately again then it will catch the event
406
+ // We have to do it asynchronously
407
+ var me = this;
408
+ setTimeout(function() {
409
+ window.addEventListener('hashchange', me.onhashchange, false);
410
+ }, 1000);
411
+ },
412
+
413
+ adjustFontSize: function() {
414
+ // Cache long lookup chains, for performance
415
+ var bodyStyle = body.style,
416
+ scrollRoot = document[document.documentElement.scrollHeight? 'documentElement' : 'body'],
417
+ innerHeight = window.innerHeight,
418
+ innerWidth = window.innerWidth,
419
+ slide = this.slides[this.slide];
420
+
421
+ // Clear previous styles
422
+ bodyStyle.fontSize = '';
423
+
424
+ if(body.classList.contains('show-thumbnails')
425
+ || slide.classList.contains('dont-resize')) {
426
+ return;
427
+ }
428
+
429
+ for(
430
+ var percent = 100;
431
+ (scrollRoot.scrollHeight > innerHeight || scrollRoot.scrollWidth > innerWidth) && percent >= 35;
432
+ percent-=5
433
+ ) {
434
+ bodyStyle.fontSize = percent + '%';
435
+ }
436
+
437
+ // Individual slide
438
+
439
+ if(slide.clientHeight && slide.clientWidth) {
440
+ // Strange FF bug: scrollHeight doesn't work properly with overflow:hidden
441
+ var previousStyle = slide.getAttribute('style');
442
+ slide.style.overflow = 'auto';
443
+
444
+ for(
445
+ ;
446
+ (slide.scrollHeight > slide.clientHeight || slide.scrollWidth > slide.clientWidth) && percent >= 35;
447
+ percent--
448
+ ) {
449
+ bodyStyle.fontSize = percent + '%';
450
+ }
451
+
452
+ slide.setAttribute('style', previousStyle);
453
+ }
454
+ },
455
+
456
+ // Is the element on the current slide?
457
+ onCurrent: function(element) {
458
+ var slide = self.getSlide(element);
459
+
460
+ if(slide) {
461
+ return '#' + slide.id === location.hash;
462
+ }
463
+
464
+ return false;
465
+ }
466
+ };
467
+
468
+ /**********************************************
469
+ * Static methods
470
+ **********************************************/
471
+
472
+ // Helper method for plugins
473
+ self.getSlide = function(element) {
474
+ var slide = element;
475
+
476
+ while (slide && slide.classList && !slide.classList.contains('slide')) {
477
+ slide = slide.parentNode;
478
+ }
479
+
480
+ return slide;
481
+ }
482
+
483
+ })(document.head || document.getElementsByTagName('head')[0], document.body);