slide-em-up 0.2.3 → 0.2.4

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.
@@ -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/solarized.css">
11
+ </head>
12
+ <body data-duration="<%= meta.duration %>">
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>slideshow = new SlideShow();</script>
34
+ </body>
35
+ </html>
@@ -0,0 +1,420 @@
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) {
11
+ return (con || document).querySelector(expr);
12
+ }
13
+ function $$(expr, con) {
14
+ return [].slice.call((con || document).querySelectorAll(expr));
15
+ }
16
+
17
+ (function(body){
18
+
19
+ // Cache <title> element, we may need it for slides that don't have titles
20
+ var documentTitle = document.title + '';
21
+
22
+ var self = window.SlideShow = function(container, slide) {
23
+ var me = this;
24
+
25
+ // Set instance
26
+ if(!window.slideshow) {
27
+ window.slideshow = this;
28
+ }
29
+
30
+ container = container || body;
31
+
32
+ // Current slide
33
+ this.slide = slide || 0;
34
+
35
+ // Current .delayed item in the slide
36
+ this.item = 0;
37
+
38
+ // Do we need to add a timer?
39
+ this.duration = container.getAttribute('data-duration');
40
+
41
+ if(this.duration > 0) {
42
+ var timer = document.createElement('div'),
43
+ declaration = 'transition: ' + this.duration * 60 + 's linear; ';
44
+
45
+ timer.id = 'timer';
46
+ timer.setAttribute('style', '-moz-' + declaration + '-webkit-' + declaration + '-o-' + declaration + '-ms-' + declaration + declaration);
47
+ container.appendChild(timer);
48
+
49
+ setTimeout(function() {
50
+ timer.className = 'end';
51
+ }, 1);
52
+ }
53
+
54
+ var delayed = $$('ol li', container);
55
+ for (var i=0; i<delayed.length; i++) {
56
+ delayed[i].className = "delayed";
57
+ }
58
+
59
+ // Get the slide elements into an array
60
+ this.slides = Array.prototype.slice.apply($$('.slide', container));
61
+
62
+ for(var i=0; i<this.slides.length; i++) {
63
+ var slide = this.slides[i]; // to speed up references
64
+
65
+ // Asign ids to slides that don't have one
66
+ if(!slide.id) {
67
+ slide.id = 'slide' + (i+1);
68
+ }
69
+
70
+ // Set data-title attribute to the title of the slide
71
+ if(!slide.title) {
72
+ // no title attribute, fetch title from heading(s)
73
+ var heading = $('hgroup', slide) || $('h1,h2,h3,h4,h5,h6', slide);
74
+
75
+ if(heading && heading.textContent.trim()) {
76
+ slide.setAttribute('data-title', heading.textContent);
77
+ }
78
+ }
79
+ else {
80
+ // The title attribute is set, use that
81
+ slide.setAttribute('data-title', slide.title);
82
+ slide.removeAttribute('title');
83
+ }
84
+ }
85
+
86
+ // If there's already a hash, update current slide number...
87
+ this.goto(location.hash.substr(1) || 0);
88
+
89
+ // ...and keep doing so every time the hash changes
90
+ this.onhashchange = function() {
91
+ me.goto(location.hash.substr(1) || 0);
92
+ };
93
+ window.addEventListener('hashchange', this.onhashchange, false);
94
+
95
+ me.startEventSourceHandler('/remote/sub/events');
96
+
97
+ if(window.name === 'projector') {
98
+ document.body.classList.add('projector');
99
+ }
100
+
101
+ // Adjust the font-size when the window is resized
102
+ addEventListener('resize', function() {
103
+ me.adjustFontSize();
104
+ }, false);
105
+
106
+ // In some browsers DOMContentLoaded is too early, so try again onload
107
+ addEventListener('load', function() {
108
+ me.adjustFontSize();
109
+ }, false);
110
+
111
+ /**
112
+ Keyboard navigation
113
+ Home : First slide
114
+ End : Last slide
115
+ Space/Up/Right arrow : Next item/slide
116
+ Ctrl + Space/Up/Right arrow : Next slide
117
+ Down/Left arrow : Previous item/slide
118
+ Ctrl + Down/Left arrow : Previous slide
119
+ (Shift instead of Ctrl works too)
120
+ */
121
+ document.addEventListener('keydown', function(evt) {
122
+ if(evt.target === body || evt.target === body.parentNode || evt.altKey) {
123
+ if(evt.keyCode >= 32 && evt.keyCode <= 40) {
124
+ evt.preventDefault();
125
+ }
126
+
127
+ switch(evt.keyCode) {
128
+ case 33: //page up
129
+ me.previous();
130
+ break;
131
+ case 34: //page down
132
+ me.next();
133
+ break;
134
+ case 35: // end
135
+ me.end();
136
+ break;
137
+ case 36: // home
138
+ me.start();
139
+ break;
140
+ case 37: // <-
141
+ case 38: // up arrow
142
+ me.previous(evt.ctrlKey || evt.shiftKey);
143
+ break;
144
+ case 32: // space
145
+ case 39: // ->
146
+ case 40: // down arrow
147
+ me.next(evt.ctrlKey || evt.shiftKey);
148
+ break;
149
+ }
150
+ }
151
+ }, false);
152
+
153
+ // Rudimentary style[scoped] polyfill
154
+ var scoped = $$('style[scoped]', container);
155
+
156
+ for(var i=scoped.length; i--;) {
157
+ var style = scoped[i],
158
+ rulez = style.sheet.cssRules,
159
+ parentid = style.parentNode.id || self.getSlide(style).id;
160
+
161
+ for(var j=rulez.length; j--;) {
162
+ var cssText = rulez[j].cssText.replace(/^|,/g, function($0) { return '#' + parentid + ' ' + $0 });
163
+
164
+ style.sheet.deleteRule(0);
165
+ style.sheet.insertRule(cssText, 0);
166
+ }
167
+ }
168
+ }
169
+
170
+ self.prototype = {
171
+ start: function() {
172
+ this.goto(0);
173
+ },
174
+
175
+ end: function() {
176
+ this.goto(this.slides.length - 1);
177
+ },
178
+
179
+ /**
180
+ @param hard {Boolean} Whether to advance to the next slide (true) or
181
+ just the next step (which could very well be showing a list item)
182
+ */
183
+ next: function(hard) {
184
+ if(!hard && this.items.length) {
185
+ // If there's no current, then just mark the first one as such
186
+ if(!this.item) {
187
+ this.items[this.item++].classList.add('current');
188
+ }
189
+ // Add .current to current item if it exists, otherwise advance to next slide
190
+ else if(this.item < this.items.length) {
191
+ classes = this.items[this.item - 1].classList; // to speed up lookups
192
+
193
+ classes.remove('current');
194
+ classes.add('displayed');
195
+
196
+ this.items[this.item++].classList.add('current');
197
+ }
198
+ else {
199
+ this.item = 0;
200
+ this.next(true);
201
+ }
202
+ }
203
+ else {
204
+ this.goto(this.slide + 1);
205
+
206
+ this.item = 0;
207
+
208
+ // Mark all items as not displayed, if there are any
209
+ if(this.items.length) {
210
+ for (var i=0; i<this.items.length; i++) {
211
+ if(this.items[i].classList) {
212
+ this.items[i].classList.remove('displayed');
213
+ this.items[i].classList.remove('current');
214
+ }
215
+ }
216
+ }
217
+ }
218
+ },
219
+
220
+ previous: function(hard) {
221
+ if(!hard && this.item > 0) {
222
+ var classes = this.items[this.item - 1].classList; // to speed up lookups
223
+
224
+ classes.remove('current');
225
+
226
+ if(this.item > 1) {
227
+ classes = this.items[--this.item - 1].classList;
228
+
229
+ classes.remove('displayed');
230
+ classes.add('current');
231
+ }
232
+ else {
233
+ this.item = 0;
234
+ }
235
+ }
236
+ else {
237
+
238
+ this.goto(this.slide - 1);
239
+
240
+ this.item = this.items.length;
241
+
242
+ // Mark all items as displayed, if there are any
243
+ if(this.items.length) {
244
+ for (var i=0; i<this.items.length; i++) {
245
+ if(this.items[i].classList) {
246
+ this.items[i].classList.add('displayed');
247
+ }
248
+ }
249
+
250
+ // Mark the last one as current
251
+ var lastItem = this.items[this.items.length - 1];
252
+
253
+ lastItem.classList.remove('displayed');
254
+ lastItem.classList.add('current');
255
+ }
256
+ }
257
+ },
258
+
259
+ /**
260
+ Go to an aribtary slide
261
+ @param which {String|Integer} Which slide (identifier or slide number)
262
+ */
263
+ goto: function(which) {
264
+ var slide;
265
+
266
+ // We have to remove it to prevent multiple calls to goto messing up
267
+ // our current item (and there's no point either, so we save on performance)
268
+ window.removeEventListener('hashchange', this.onhashchange, false);
269
+
270
+ if(which + 0 === which && which in this.slides) { // Argument is a valid slide number
271
+ this.slide = which;
272
+
273
+ slide = this.slides[this.slide];
274
+ location.hash = '#' + slide.id;
275
+ }
276
+ else if(which + '' === which) { // Argument is a slide id
277
+ slide = document.getElementById(which);
278
+
279
+ if(slide) {
280
+ this.slide = this.slides.indexOf(slide);
281
+ location.hash = '#' + which;
282
+ }
283
+ }
284
+
285
+ if(slide) { // Slide actually changed, perform any other tasks needed
286
+ document.title = slide.getAttribute('data-title') || documentTitle;
287
+
288
+ this.adjustFontSize();
289
+
290
+ // Update items collection
291
+ this.items = $$('.delayed, .delayed-children > *', this.slides[this.slide]);
292
+ this.item = 0;
293
+
294
+ // Tell other windows
295
+ if(this.projector && this.projector.slideshow && this.projector.slideshow.slide != this.slide) {
296
+ this.projector.slideshow.goto(this.slide);
297
+ }
298
+
299
+ if(window.opener && opener.slideshow && opener.slideshow.slide != this.slide) {
300
+ opener.slideshow.goto(this.slide);
301
+ }
302
+
303
+ // Update next/previous
304
+ for (var i=this.slides.length; i--;) {
305
+ this.slides[i].classList.remove('previous');
306
+ this.slides[i].classList.remove('next');
307
+ }
308
+
309
+ this.slides.previous = this.slides[this.slide-1];
310
+ this.slides.next = this.slides[this.slide+1];
311
+
312
+ this.slides.previous && this.slides.previous.classList.add('previous');
313
+ this.slides.next && this.slides.next.classList.add('next');
314
+ }
315
+
316
+ // If you attach the listener immediately again then it will catch the event
317
+ // We have to do it asynchronously
318
+ var me = this;
319
+ setTimeout(function() {
320
+ window.addEventListener('hashchange', me.onhashchange, false);
321
+ }, 1000);
322
+ },
323
+
324
+ adjustFontSize: function() {
325
+ // Cache long lookup chains, for performance
326
+ var bodyStyle = body.style,
327
+ scrollRoot = document[document.documentElement.scrollHeight? 'documentElement' : 'body'],
328
+ innerHeight = window.innerHeight,
329
+ innerWidth = window.innerWidth,
330
+ slide = this.slides[this.slide];
331
+
332
+ // Clear previous styles
333
+ bodyStyle.fontSize = '';
334
+
335
+ if(body.classList.contains('show-thumbnails')
336
+ || slide.classList.contains('dont-resize')) {
337
+ return;
338
+ }
339
+
340
+ for(
341
+ var percent = 100;
342
+ (scrollRoot.scrollHeight > innerHeight || scrollRoot.scrollWidth > innerWidth) && percent >= 35;
343
+ percent-=5
344
+ ) {
345
+ bodyStyle.fontSize = percent + '%';
346
+ }
347
+
348
+ // Individual slide
349
+
350
+ if(slide.clientHeight && slide.clientWidth) {
351
+ // Strange FF bug: scrollHeight doesn't work properly with overflow:hidden
352
+ var previousStyle = slide.getAttribute('style');
353
+ slide.style.overflow = 'auto';
354
+
355
+ for(
356
+ ;
357
+ (slide.scrollHeight > slide.clientHeight || slide.scrollWidth > slide.clientWidth) && percent >= 35;
358
+ percent--
359
+ ) {
360
+ bodyStyle.fontSize = percent + '%';
361
+ }
362
+
363
+ slide.setAttribute('style', previousStyle);
364
+ }
365
+ },
366
+
367
+ // Is the element on the current slide?
368
+ onCurrent: function(element) {
369
+ var slide = self.getSlide(element);
370
+
371
+ if(slide) {
372
+ return '#' + slide.id === location.hash;
373
+ }
374
+
375
+ return false;
376
+ },
377
+
378
+ startEventSourceHandler: function(uri) {
379
+ if (window['EventSource'] == undefined) return ;
380
+
381
+ var source = new EventSource(uri);
382
+ var me = this;
383
+
384
+ source.onmessage = function(e) {
385
+ switch(e.data){
386
+ case 'next':
387
+ me.next();
388
+ break;
389
+ case 'prev':
390
+ me.previous();
391
+ break;
392
+ case 'up':
393
+ me.end();
394
+ break;
395
+ case 'down':
396
+ me.start();
397
+ break;
398
+ default:
399
+ console.log(e);
400
+ };
401
+ };
402
+ }
403
+ };
404
+
405
+ /**********************************************
406
+ * Static methods
407
+ **********************************************/
408
+
409
+ // Helper method for plugins
410
+ self.getSlide = function(element) {
411
+ var slide = element;
412
+
413
+ while (slide && slide.classList && !slide.classList.contains('slide')) {
414
+ slide = slide.parentNode;
415
+ }
416
+
417
+ return slide;
418
+ }
419
+
420
+ })(document.body);