prezio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in prezio.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Adam Pohorecki
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,52 @@
1
+ # Prezio
2
+
3
+ A tool to generate HTML5/CSS slideshows.
4
+
5
+ Uses [DZSlides][dzslides] HTML template and [pygments.rb][pygments] for syntax highlighting.
6
+
7
+ ## Installation
8
+
9
+ Install the gem using:
10
+
11
+ $ gem install prezio
12
+
13
+ ## Usage
14
+
15
+ Prezio converts simple html files into presentations.
16
+
17
+ The HTML file should look like this:
18
+
19
+ ```html
20
+ <title>The Title Of Your Presentation</title>
21
+
22
+ <!-- One section is one slide -->
23
+ <section>
24
+ <h1>My Presentation</h1>
25
+ <footer>by John Doe</footer>
26
+ </section>
27
+
28
+ <section>
29
+ <!-- Any HTML -->
30
+ <p>Some random text</p>
31
+ </section>
32
+
33
+ <section>
34
+ <!-- This will be highlighted -->
35
+ <code lang="ruby">
36
+ def greet(name)
37
+ println "Hello, #{name}!"
38
+ end
39
+ </code>
40
+ </section>
41
+ ```
42
+
43
+ Convert the template to presentation using the following command:
44
+
45
+ $ prezio convert template.html presentation.html
46
+
47
+ While you are developing the presentation, it might be useful to run prezio in preview mode:
48
+
49
+ $ prezio preview template.html
50
+
51
+ [dzslides]: https://github.com/paulrouget/dzslides
52
+ [pygments]: https://github.com/tmm1/pygments.rb/
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/prezio'
4
+
5
+ require 'commander/import'
6
+
7
+ program :name, 'Prezio'
8
+ program :version, Prezio::VERSION
9
+ program :description, 'HTML5 presentation generator'
10
+
11
+ command :convert do |c|
12
+ c.syntax = 'prezio convert <input.html> <output.html>'
13
+ c.description = 'Transforms input.html into output.html'
14
+
15
+ c.action do |args, options|
16
+ if args.size != 2
17
+ say_error "convert takes exactly 2 arguments!"
18
+ exit(1)
19
+ end
20
+
21
+ Prezio.convert(args[0], args[1])
22
+
23
+ say "Converted."
24
+ end
25
+ end
26
+
27
+ command :preview do |c|
28
+ c.syntax = 'prezio preview <input.html>'
29
+ c.description = 'Starts a server that transforms input.html on each request'
30
+
31
+ c.action do |args, options|
32
+ if args.size != 1
33
+ say_error "convert takes exactly 1 argument!"
34
+ exit(1)
35
+ end
36
+
37
+ require 'sinatra'
38
+ require 'tempfile'
39
+
40
+ template = args[0]
41
+ out_file = Tempfile.new(File.basename(template)).path
42
+
43
+ get "/" do
44
+ Prezio.convert(template, out_file)
45
+ File.read(out_file)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ module Prezio
2
+ def self.convert(template_file, presentation_file)
3
+ Prezio::Converter.convert(template_file, presentation_file)
4
+ end
5
+ end
6
+
7
+ Dir[File.expand_path("../**/*.rb", __FILE__)].each do |file|
8
+ require file
9
+ end
@@ -0,0 +1,10 @@
1
+ module Prezio
2
+ class Converter
3
+ def self.convert(template_file, presentation_file)
4
+ content = File.read(template_file)
5
+ content = SyntaxHighlighter.highlight(content)
6
+ content = DZSlidesWrapper.wrap(content)
7
+ File.open(presentation_file, "w") {|f| f.write(content) }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,616 @@
1
+ <!DOCTYPE html>
2
+
3
+ <meta charset="utf-8">
4
+
5
+ {{*the slides*}}
6
+
7
+ <!-- Maybe a font from http://www.google.com/webfonts ? -->
8
+ <link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet'>
9
+
10
+ <style>
11
+ html, .view body { background-color: black; counter-reset: slideidx; }
12
+ body, .view section { background-color: white; border-radius: 12px }
13
+ /* A section is a slide. It's size is 800x600, and this will never change */
14
+ section, .view head > title {
15
+ /* The font from Google */
16
+ font-family: 'Oswald', arial, serif;
17
+ font-size: 30px;
18
+ }
19
+
20
+ .view section:after {
21
+ counter-increment: slideidx;
22
+ content: counter(slideidx, decimal-leading-zero);
23
+ position: absolute; bottom: -80px; right: 100px;
24
+ color: white;
25
+ }
26
+
27
+ .view head > title {
28
+ color: white;
29
+ text-align: center;
30
+ margin: 1em 0 1em 0;
31
+ }
32
+
33
+ h1, h2 {
34
+ margin-top: 200px;
35
+ text-align: center;
36
+ font-size: 80px;
37
+ }
38
+ h3 {
39
+ margin: 100px 0 50px 100px;
40
+ }
41
+
42
+ ul {
43
+ margin: 50px 200px;
44
+ }
45
+
46
+ p {
47
+ margin: 75px;
48
+ font-size: 50px;
49
+ }
50
+
51
+ blockquote {
52
+ height: 100%;
53
+ background-color: black;
54
+ color: white;
55
+ font-size: 60px;
56
+ padding: 50px;
57
+ }
58
+ blockquote:before {
59
+ content: open-quote;
60
+ }
61
+ blockquote:after {
62
+ content: close-quote;
63
+ }
64
+
65
+ /* Figures are displayed full-page, with the caption
66
+ on top of the image/video */
67
+ figure {
68
+ background-color: black;
69
+ width: 100%;
70
+ height: 100%;
71
+ }
72
+ figure > * {
73
+ position: absolute;
74
+ }
75
+ figure > img, figure > video {
76
+ width: 100%; height: 100%;
77
+ }
78
+ figcaption {
79
+ margin: 70px;
80
+ font-size: 50px;
81
+ }
82
+
83
+ footer {
84
+ position: absolute;
85
+ bottom: 0;
86
+ width: 100%;
87
+ padding: 40px;
88
+ text-align: right;
89
+ background-color: #F3F4F8;
90
+ border-top: 1px solid #CCC;
91
+ }
92
+
93
+ /* Transition effect */
94
+ /* Feel free to change the transition effect for original
95
+ animations. See here:
96
+ https://developer.mozilla.org/en/CSS/CSS_transitions
97
+ How to use CSS3 Transitions: */
98
+ section {
99
+ -moz-transition: left 400ms linear 0s;
100
+ -webkit-transition: left 400ms linear 0s;
101
+ -ms-transition: left 400ms linear 0s;
102
+ transition: left 400ms linear 0s;
103
+ }
104
+ .view section {
105
+ -moz-transition: none;
106
+ -webkit-transition: none;
107
+ -ms-transition: none;
108
+ transition: none;
109
+ }
110
+
111
+ .view section[aria-selected] {
112
+ border: 5px red solid;
113
+ }
114
+
115
+ /* Before */
116
+ section { left: -150%; }
117
+ /* Now */
118
+ section[aria-selected] { left: 0; }
119
+ /* After */
120
+ section[aria-selected] ~ section { left: +150%; }
121
+
122
+ /* Incremental elements */
123
+
124
+ /* By default, visible */
125
+ .incremental > * { opacity: 1; }
126
+
127
+ /* The current item */
128
+ .incremental > *[aria-selected] { opacity: 1; }
129
+
130
+ /* The items to-be-selected */
131
+ .incremental > *[aria-selected] ~ * { opacity: 0; }
132
+
133
+ /* The progressbar, at the bottom of the slides, show the global
134
+ progress of the presentation. */
135
+ #progress-bar {
136
+ height: 2px;
137
+ background: #AAA;
138
+ }
139
+ </style>
140
+
141
+ <!-- {{{{ dzslides core
142
+ #
143
+ #
144
+ # __ __ __ . __ ___ __
145
+ # | \ / /__` | | | \ |__ /__`
146
+ # |__/ /_ .__/ |___ | |__/ |___ .__/ core :€
147
+ #
148
+ #
149
+ # The following block of code is not supposed to be edited.
150
+ # But if you want to change the behavior of these slides,
151
+ # feel free to hack it!
152
+ #
153
+ -->
154
+
155
+ <div id="progress-bar"></div>
156
+
157
+ <!-- Default Style -->
158
+ <style>
159
+ * { margin: 0; padding: 0; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
160
+ details { display: none; }
161
+ body {
162
+ width: 800px; height: 600px;
163
+ margin-left: -400px; margin-top: -300px;
164
+ position: absolute; top: 50%; left: 50%;
165
+ overflow: hidden;
166
+ display: none;
167
+ }
168
+ .view body {
169
+ position: static;
170
+ margin: 0; padding: 0;
171
+ width: 100%; height: 100%;
172
+ display: inline-block;
173
+ overflow: visible; overflow-x: hidden;
174
+ /* undo Dz.onresize */
175
+ transform: none !important;
176
+ -moz-transform: none !important;
177
+ -webkit-transform: none !important;
178
+ -o-transform: none !important;
179
+ -ms-transform: none !important;
180
+ }
181
+ .view head, .view head > title { display: block }
182
+ section {
183
+ position: absolute;
184
+ pointer-events: none;
185
+ width: 100%; height: 100%;
186
+ }
187
+ .view section {
188
+ pointer-events: auto;
189
+ position: static;
190
+ width: 800px; height: 600px;
191
+ margin: -150px -200px;
192
+ float: left;
193
+
194
+ transform: scale(.4);
195
+ -moz-transform: scale(.4);
196
+ -webkit-transform: scale(.4);
197
+ -o-transform: scale(.4);
198
+ -ms-transform: scale(.4);
199
+ }
200
+ .view section > * { pointer-events: none; }
201
+ section[aria-selected] { pointer-events: auto; }
202
+ html { overflow: hidden; }
203
+ html.view { overflow: visible; }
204
+ body.loaded { display: block; }
205
+ .incremental {visibility: hidden; }
206
+ .incremental[active] {visibility: visible; }
207
+ #progress-bar{
208
+ bottom: 0;
209
+ position: absolute;
210
+ -moz-transition: width 400ms linear 0s;
211
+ -webkit-transition: width 400ms linear 0s;
212
+ -ms-transition: width 400ms linear 0s;
213
+ transition: width 400ms linear 0s;
214
+ }
215
+ .view #progress-bar {
216
+ display: none;
217
+ }
218
+ </style>
219
+
220
+ <script>
221
+ var Dz = {
222
+ remoteWindows: [],
223
+ idx: -1,
224
+ step: 0,
225
+ html: null,
226
+ slides: null,
227
+ progressBar : null,
228
+ params: {
229
+ autoplay: "1"
230
+ }
231
+ };
232
+
233
+ Dz.init = function() {
234
+ document.body.className = "loaded";
235
+ this.slides = Array.prototype.slice.call($$("body > section"));
236
+ this.progressBar = $("#progress-bar");
237
+ this.html = document.body.parentNode;
238
+ this.setupParams();
239
+ this.onhashchange();
240
+ this.setupTouchEvents();
241
+ this.onresize();
242
+ this.setupView();
243
+ }
244
+
245
+ Dz.setupParams = function() {
246
+ var p = window.location.search.substr(1).split('&');
247
+ p.forEach(function(e, i, a) {
248
+ var keyVal = e.split('=');
249
+ Dz.params[keyVal[0]] = decodeURIComponent(keyVal[1]);
250
+ });
251
+ // Specific params handling
252
+ if (!+this.params.autoplay)
253
+ $$.forEach($$("video"), function(v){ v.controls = true });
254
+ }
255
+
256
+ Dz.onkeydown = function(aEvent) {
257
+ // Don't intercept keyboard shortcuts
258
+ if (aEvent.altKey
259
+ || aEvent.ctrlKey
260
+ || aEvent.metaKey
261
+ || aEvent.shiftKey) {
262
+ return;
263
+ }
264
+ if ( aEvent.keyCode == 37 // left arrow
265
+ || aEvent.keyCode == 38 // up arrow
266
+ || aEvent.keyCode == 33 // page up
267
+ ) {
268
+ aEvent.preventDefault();
269
+ this.back();
270
+ }
271
+ if ( aEvent.keyCode == 39 // right arrow
272
+ || aEvent.keyCode == 40 // down arrow
273
+ || aEvent.keyCode == 34 // page down
274
+ ) {
275
+ aEvent.preventDefault();
276
+ this.forward();
277
+ }
278
+ if (aEvent.keyCode == 35) { // end
279
+ aEvent.preventDefault();
280
+ this.goEnd();
281
+ }
282
+ if (aEvent.keyCode == 36) { // home
283
+ aEvent.preventDefault();
284
+ this.goStart();
285
+ }
286
+ if (aEvent.keyCode == 32) { // space
287
+ aEvent.preventDefault();
288
+ this.toggleContent();
289
+ }
290
+ if (aEvent.keyCode == 70) { // f
291
+ aEvent.preventDefault();
292
+ this.goFullscreen();
293
+ }
294
+ if (aEvent.keyCode == 79) { // o
295
+ aEvent.preventDefault();
296
+ this.toggleView();
297
+ }
298
+ }
299
+
300
+ /* Touch Events */
301
+
302
+ Dz.setupTouchEvents = function() {
303
+ var orgX, newX;
304
+ var tracking = false;
305
+
306
+ var db = document.body;
307
+ db.addEventListener("touchstart", start.bind(this), false);
308
+ db.addEventListener("touchmove", move.bind(this), false);
309
+
310
+ function start(aEvent) {
311
+ aEvent.preventDefault();
312
+ tracking = true;
313
+ orgX = aEvent.changedTouches[0].pageX;
314
+ }
315
+
316
+ function move(aEvent) {
317
+ if (!tracking) return;
318
+ newX = aEvent.changedTouches[0].pageX;
319
+ if (orgX - newX > 100) {
320
+ tracking = false;
321
+ this.forward();
322
+ } else {
323
+ if (orgX - newX < -100) {
324
+ tracking = false;
325
+ this.back();
326
+ }
327
+ }
328
+ }
329
+ }
330
+
331
+ Dz.setupView = function() {
332
+ document.body.addEventListener("click", function ( e ) {
333
+ if (!Dz.html.classList.contains("view")) return;
334
+ if (!e.target || e.target.nodeName != "SECTION") return;
335
+
336
+ Dz.html.classList.remove("view");
337
+ Dz.setCursor(Dz.slides.indexOf(e.target) + 1);
338
+ }, false);
339
+ }
340
+
341
+ /* Adapt the size of the slides to the window */
342
+
343
+ Dz.onresize = function() {
344
+ var db = document.body;
345
+ var sx = db.clientWidth / window.innerWidth;
346
+ var sy = db.clientHeight / window.innerHeight;
347
+ var transform = "scale(" + (1/Math.max(sx, sy)) + ")";
348
+
349
+ db.style.MozTransform = transform;
350
+ db.style.WebkitTransform = transform;
351
+ db.style.OTransform = transform;
352
+ db.style.msTransform = transform;
353
+ db.style.transform = transform;
354
+ }
355
+
356
+
357
+ Dz.getDetails = function(aIdx) {
358
+ var s = $("section:nth-of-type(" + aIdx + ")");
359
+ var d = s.$("details");
360
+ return d ? d.innerHTML : "";
361
+ }
362
+
363
+ Dz.onmessage = function(aEvent) {
364
+ var argv = aEvent.data.split(" "), argc = argv.length;
365
+ argv.forEach(function(e, i, a) { a[i] = decodeURIComponent(e) });
366
+ var win = aEvent.source;
367
+ if (argv[0] === "REGISTER" && argc === 1) {
368
+ this.remoteWindows.push(win);
369
+ this.postMsg(win, "REGISTERED", document.title, this.slides.length);
370
+ this.postMsg(win, "CURSOR", this.idx + "." + this.step);
371
+ return;
372
+ }
373
+ if (argv[0] === "BACK" && argc === 1)
374
+ this.back();
375
+ if (argv[0] === "FORWARD" && argc === 1)
376
+ this.forward();
377
+ if (argv[0] === "START" && argc === 1)
378
+ this.goStart();
379
+ if (argv[0] === "END" && argc === 1)
380
+ this.goEnd();
381
+ if (argv[0] === "TOGGLE_CONTENT" && argc === 1)
382
+ this.toggleContent();
383
+ if (argv[0] === "SET_CURSOR" && argc === 2)
384
+ window.location.hash = "#" + argv[1];
385
+ if (argv[0] === "GET_CURSOR" && argc === 1)
386
+ this.postMsg(win, "CURSOR", this.idx + "." + this.step);
387
+ if (argv[0] === "GET_NOTES" && argc === 1)
388
+ this.postMsg(win, "NOTES", this.getDetails(this.idx));
389
+ }
390
+
391
+ Dz.toggleContent = function() {
392
+ // If a Video is present in this new slide, play it.
393
+ // If a Video is present in the previous slide, stop it.
394
+ var s = $("section[aria-selected]");
395
+ if (s) {
396
+ var video = s.$("video");
397
+ if (video) {
398
+ if (video.ended || video.paused) {
399
+ video.play();
400
+ } else {
401
+ video.pause();
402
+ }
403
+ }
404
+ }
405
+ }
406
+
407
+ Dz.setCursor = function(aIdx, aStep) {
408
+ // If the user change the slide number in the URL bar, jump
409
+ // to this slide.
410
+ aStep = (aStep != 0 && typeof aStep !== "undefined") ? "." + aStep : ".0";
411
+ window.location.hash = "#" + aIdx + aStep;
412
+ }
413
+
414
+ Dz.onhashchange = function() {
415
+ var cursor = window.location.hash.split("#"),
416
+ newidx = 1,
417
+ newstep = 0;
418
+ if (cursor.length == 2) {
419
+ newidx = ~~cursor[1].split(".")[0];
420
+ newstep = ~~cursor[1].split(".")[1];
421
+ if (newstep > Dz.slides[newidx - 1].$$('.incremental > *').length) {
422
+ newstep = 0;
423
+ newidx++;
424
+ }
425
+ }
426
+ this.setProgress(newidx, newstep);
427
+ if (newidx != this.idx) {
428
+ this.setSlide(newidx);
429
+ }
430
+ if (newstep != this.step) {
431
+ this.setIncremental(newstep);
432
+ }
433
+ for (var i = 0; i < this.remoteWindows.length; i++) {
434
+ this.postMsg(this.remoteWindows[i], "CURSOR", this.idx + "." + this.step);
435
+ }
436
+ }
437
+
438
+ Dz.back = function() {
439
+ if (this.idx == 1 && this.step == 0) {
440
+ return;
441
+ }
442
+ if (this.step == 0) {
443
+ this.setCursor(this.idx - 1,
444
+ this.slides[this.idx - 2].$$('.incremental > *').length);
445
+ } else {
446
+ this.setCursor(this.idx, this.step - 1);
447
+ }
448
+ }
449
+
450
+ Dz.forward = function() {
451
+ if (this.idx >= this.slides.length &&
452
+ this.step >= this.slides[this.idx - 1].$$('.incremental > *').length) {
453
+ return;
454
+ }
455
+ if (this.step >= this.slides[this.idx - 1].$$('.incremental > *').length) {
456
+ this.setCursor(this.idx + 1, 0);
457
+ } else {
458
+ this.setCursor(this.idx, this.step + 1);
459
+ }
460
+ }
461
+
462
+ Dz.goStart = function() {
463
+ this.setCursor(1, 0);
464
+ }
465
+
466
+ Dz.goEnd = function() {
467
+ var lastIdx = this.slides.length;
468
+ var lastStep = this.slides[lastIdx - 1].$$('.incremental > *').length;
469
+ this.setCursor(lastIdx, lastStep);
470
+ }
471
+
472
+ Dz.toggleView = function() {
473
+ this.html.classList.toggle("view");
474
+
475
+ if (this.html.classList.contains("view")) {
476
+ $("section[aria-selected]").scrollIntoView(true);
477
+ }
478
+ }
479
+
480
+ Dz.setSlide = function(aIdx) {
481
+ this.idx = aIdx;
482
+ var old = $("section[aria-selected]");
483
+ var next = $("section:nth-of-type("+ this.idx +")");
484
+ if (old) {
485
+ old.removeAttribute("aria-selected");
486
+ var video = old.$("video");
487
+ if (video) {
488
+ video.pause();
489
+ }
490
+ }
491
+ if (next) {
492
+ next.setAttribute("aria-selected", "true");
493
+ if (this.html.classList.contains("view")) {
494
+ next.scrollIntoView();
495
+ }
496
+ var video = next.$("video");
497
+ if (video && !!+this.params.autoplay) {
498
+ video.play();
499
+ }
500
+ } else {
501
+ // That should not happen
502
+ this.idx = -1;
503
+ // console.warn("Slide doesn't exist.");
504
+ }
505
+ }
506
+
507
+ Dz.setIncremental = function(aStep) {
508
+ this.step = aStep;
509
+ var old = this.slides[this.idx - 1].$('.incremental > *[aria-selected]');
510
+ if (old) {
511
+ old.removeAttribute('aria-selected');
512
+ }
513
+ var incrementals = $$('.incremental');
514
+ if (this.step <= 0) {
515
+ $$.forEach(incrementals, function(aNode) {
516
+ aNode.removeAttribute('active');
517
+ });
518
+ return;
519
+ }
520
+ var next = this.slides[this.idx - 1].$$('.incremental > *')[this.step - 1];
521
+ if (next) {
522
+ next.setAttribute('aria-selected', true);
523
+ next.parentNode.setAttribute('active', true);
524
+ var found = false;
525
+ $$.forEach(incrementals, function(aNode) {
526
+ if (aNode != next.parentNode)
527
+ if (found)
528
+ aNode.removeAttribute('active');
529
+ else
530
+ aNode.setAttribute('active', true);
531
+ else
532
+ found = true;
533
+ });
534
+ } else {
535
+ setCursor(this.idx, 0);
536
+ }
537
+ return next;
538
+ }
539
+
540
+ Dz.goFullscreen = function() {
541
+ var html = $('html'),
542
+ requestFullscreen = html.requestFullscreen || html.requestFullScreen || html.mozRequestFullScreen || html.webkitRequestFullScreen;
543
+ if (requestFullscreen) {
544
+ requestFullscreen.apply(html);
545
+ }
546
+ }
547
+
548
+ Dz.setProgress = function(aIdx, aStep) {
549
+ var slide = $("section:nth-of-type("+ aIdx +")");
550
+ if (!slide)
551
+ return;
552
+ var steps = slide.$$('.incremental > *').length + 1,
553
+ slideSize = 100 / (this.slides.length - 1),
554
+ stepSize = slideSize / steps;
555
+ this.progressBar.style.width = ((aIdx - 1) * slideSize + aStep * stepSize) + '%';
556
+ }
557
+
558
+ Dz.postMsg = function(aWin, aMsg) { // [arg0, [arg1...]]
559
+ aMsg = [aMsg];
560
+ for (var i = 2; i < arguments.length; i++)
561
+ aMsg.push(encodeURIComponent(arguments[i]));
562
+ aWin.postMessage(aMsg.join(" "), "*");
563
+ }
564
+
565
+ function init() {
566
+ Dz.init();
567
+ window.onkeydown = Dz.onkeydown.bind(Dz);
568
+ window.onresize = Dz.onresize.bind(Dz);
569
+ window.onhashchange = Dz.onhashchange.bind(Dz);
570
+ window.onmessage = Dz.onmessage.bind(Dz);
571
+ }
572
+
573
+ window.onload = init;
574
+ </script>
575
+
576
+
577
+ <script> // Helpers
578
+ if (!Function.prototype.bind) {
579
+ Function.prototype.bind = function (oThis) {
580
+
581
+ // closest thing possible to the ECMAScript 5 internal IsCallable
582
+ // function
583
+ if (typeof this !== "function")
584
+ throw new TypeError(
585
+ "Function.prototype.bind - what is trying to be fBound is not callable"
586
+ );
587
+
588
+ var aArgs = Array.prototype.slice.call(arguments, 1),
589
+ fToBind = this,
590
+ fNOP = function () {},
591
+ fBound = function () {
592
+ return fToBind.apply( this instanceof fNOP ? this : oThis || window,
593
+ aArgs.concat(Array.prototype.slice.call(arguments)));
594
+ };
595
+
596
+ fNOP.prototype = this.prototype;
597
+ fBound.prototype = new fNOP();
598
+
599
+ return fBound;
600
+ };
601
+ }
602
+
603
+ var $ = (HTMLElement.prototype.$ = function(aQuery) {
604
+ return this.querySelector(aQuery);
605
+ }).bind(document);
606
+
607
+ var $$ = (HTMLElement.prototype.$$ = function(aQuery) {
608
+ return this.querySelectorAll(aQuery);
609
+ }).bind(document);
610
+
611
+ $$.forEach = function(nodeList, fun) {
612
+ Array.prototype.forEach.call(nodeList, fun);
613
+ }
614
+
615
+ </script>
616
+ <!-- vim: set fdm=marker: }}} -->
@@ -0,0 +1,17 @@
1
+ module Prezio
2
+ class DZSlidesWrapper
3
+ def self.wrap(content)
4
+ template.gsub('{{*the slides*}}', content)
5
+ end
6
+
7
+ private
8
+
9
+ def self.template
10
+ @template ||= File.read(template_file_name)
11
+ end
12
+
13
+ def self.template_file_name
14
+ File.expand_path("../dz_slides/template.html", __FILE__)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,93 @@
1
+ <style>
2
+ .highlight {
3
+ background-color: #FDF6E3;
4
+ border-radius: 5px;
5
+ box-shadow: 5px 5px 5px #ccc;
6
+ border-collapse: collapse;
7
+ border: 1px solid #ebe4ce;
8
+ }
9
+ .highlight .line-numbers {
10
+ width: 30px;
11
+ text-align: right;
12
+ background-color: #FDF8E8;
13
+ color: #93A1A1;
14
+ border-right: 1px solid #EBE4CE;
15
+ }
16
+ .highlight .line-number {
17
+ padding-right: 7px;
18
+ }
19
+ .highlight .code {
20
+ padding-left: 5px;
21
+ }
22
+
23
+ .highlight { margin: 73px; }
24
+ .highlight .hll { background-color: #ffffcc }
25
+ .highlight .c { color: #586E75 } /* Comment */
26
+ .highlight .err { color: #93A1A1 } /* Error */
27
+ .highlight .g { color: #93A1A1 } /* Generic */
28
+ .highlight .k { color: #859900 } /* Keyword */
29
+ .highlight .l { color: #93A1A1 } /* Literal */
30
+ .highlight .n { color: #93A1A1 } /* Name */
31
+ .highlight .o { color: #859900 } /* Operator */
32
+ .highlight .x { color: #CB4B16 } /* Other */
33
+ .highlight .p { color: #93A1A1 } /* Punctuation */
34
+ .highlight .cm { color: #586E75 } /* Comment.Multiline */
35
+ .highlight .cp { color: #859900 } /* Comment.Preproc */
36
+ .highlight .c1 { color: #586E75 } /* Comment.Single */
37
+ .highlight .cs { color: #859900 } /* Comment.Special */
38
+ .highlight .gd { color: #2AA198 } /* Generic.Deleted */
39
+ .highlight .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */
40
+ .highlight .gr { color: #DC322F } /* Generic.Error */
41
+ .highlight .gh { color: #CB4B16 } /* Generic.Heading */
42
+ .highlight .gi { color: #859900 } /* Generic.Inserted */
43
+ .highlight .go { color: #93A1A1 } /* Generic.Output */
44
+ .highlight .gp { color: #93A1A1 } /* Generic.Prompt */
45
+ .highlight .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */
46
+ .highlight .gu { color: #CB4B16 } /* Generic.Subheading */
47
+ .highlight .gt { color: #93A1A1 } /* Generic.Traceback */
48
+ .highlight .kc { color: #CB4B16 } /* Keyword.Constant */
49
+ .highlight .kd { color: #268BD2 } /* Keyword.Declaration */
50
+ .highlight .kn { color: #859900 } /* Keyword.Namespace */
51
+ .highlight .kp { color: #859900 } /* Keyword.Pseudo */
52
+ .highlight .kr { color: #268BD2 } /* Keyword.Reserved */
53
+ .highlight .kt { color: #DC322F } /* Keyword.Type */
54
+ .highlight .ld { color: #93A1A1 } /* Literal.Date */
55
+ .highlight .m { color: #2AA198 } /* Literal.Number */
56
+ .highlight .s { color: #2AA198 } /* Literal.String */
57
+ .highlight .na { color: #93A1A1 } /* Name.Attribute */
58
+ .highlight .nb { color: #B58900 } /* Name.Builtin */
59
+ .highlight .nc { color: #268BD2 } /* Name.Class */
60
+ .highlight .no { color: #CB4B16 } /* Name.Constant */
61
+ .highlight .nd { color: #268BD2 } /* Name.Decorator */
62
+ .highlight .ni { color: #CB4B16 } /* Name.Entity */
63
+ .highlight .ne { color: #CB4B16 } /* Name.Exception */
64
+ .highlight .nf { color: #268BD2 } /* Name.Function */
65
+ .highlight .nl { color: #93A1A1 } /* Name.Label */
66
+ .highlight .nn { color: #93A1A1 } /* Name.Namespace */
67
+ .highlight .nx { color: #93A1A1 } /* Name.Other */
68
+ .highlight .py { color: #93A1A1 } /* Name.Property */
69
+ .highlight .nt { color: #268BD2 } /* Name.Tag */
70
+ .highlight .nv { color: #268BD2 } /* Name.Variable */
71
+ .highlight .ow { color: #859900 } /* Operator.Word */
72
+ .highlight .w { color: #93A1A1 } /* Text.Whitespace */
73
+ .highlight .mf { color: #2AA198 } /* Literal.Number.Float */
74
+ .highlight .mh { color: #2AA198 } /* Literal.Number.Hex */
75
+ .highlight .mi { color: #2AA198 } /* Literal.Number.Integer */
76
+ .highlight .mo { color: #2AA198 } /* Literal.Number.Oct */
77
+ .highlight .sb { color: #586E75 } /* Literal.String.Backtick */
78
+ .highlight .sc { color: #2AA198 } /* Literal.String.Char */
79
+ .highlight .sd { color: #93A1A1 } /* Literal.String.Doc */
80
+ .highlight .s2 { color: #2AA198 } /* Literal.String.Double */
81
+ .highlight .se { color: #CB4B16 } /* Literal.String.Escape */
82
+ .highlight .sh { color: #93A1A1 } /* Literal.String.Heredoc */
83
+ .highlight .si { color: #2AA198 } /* Literal.String.Interpol */
84
+ .highlight .sx { color: #2AA198 } /* Literal.String.Other */
85
+ .highlight .sr { color: #DC322F } /* Literal.String.Regex */
86
+ .highlight .s1 { color: #2AA198 } /* Literal.String.Single */
87
+ .highlight .ss { color: #2AA198 } /* Literal.String.Symbol */
88
+ .highlight .bp { color: #268BD2 } /* Name.Builtin.Pseudo */
89
+ .highlight .vc { color: #268BD2 } /* Name.Variable.Class */
90
+ .highlight .vg { color: #268BD2 } /* Name.Variable.Global */
91
+ .highlight .vi { color: #268BD2 } /* Name.Variable.Instance */
92
+ .highlight .il { color: #2AA198 } /* Literal.Number.Integer.Long */
93
+ .highlight </style>
@@ -0,0 +1,55 @@
1
+ require 'nokogiri'
2
+ require 'pygments'
3
+
4
+ module Prezio
5
+ class SyntaxHighlighter
6
+ def self.highlight(html)
7
+ new(html).to_s
8
+ end
9
+
10
+ def initialize(html)
11
+ @html = html
12
+ end
13
+
14
+ def to_s
15
+ doc = Nokogiri::HTML.fragment(@html)
16
+
17
+ replace_code_tags(doc)
18
+ add_highliting_styles(doc)
19
+
20
+ doc.to_s
21
+ end
22
+
23
+ private
24
+
25
+ def replace_code_tags(doc)
26
+ doc.css("code").each do |node|
27
+ node.replace(highlight(node))
28
+ end
29
+ end
30
+
31
+ def add_highliting_styles(doc)
32
+ styles_file = File.expand_path("../octopress/highlight.html", __FILE__)
33
+ html = File.read(styles_file)
34
+ doc.add_child(html)
35
+ end
36
+
37
+ def highlight(node)
38
+ text = node.inner_html.to_s
39
+ code = Pygments.highlight(text, lexer: node['lang'])
40
+ code = code.match(/<pre>(.*)<\/pre>/m)[1].to_s.gsub(/\s*\Z/, '')
41
+ tableize_code(code, node['lang'])
42
+ end
43
+
44
+ # taken from octopress
45
+ def tableize_code (str, lang = '')
46
+ table = '<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers">'
47
+ code = ''
48
+ str.lines.each_with_index do |line,index|
49
+ table += "<span class='line-number'>#{index+1}</span>\n"
50
+ code += "<span class='line'>#{line}</span>"
51
+ end
52
+ table += "</pre></td><td class='code'><pre><code class='#{lang}'>#{code}</code></pre></td></tr></table></div>"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module Prezio
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/prezio/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Adam Pohorecki"]
6
+ gem.email = ["adam@pohorecki.pl"]
7
+ gem.description = %q{HTML5 presentation generator}
8
+ gem.summary = %q{HTML5 presentation generator}
9
+ gem.homepage = "http://github.com/psyho/prezio"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "prezio"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Prezio::VERSION
17
+
18
+ gem.add_dependency 'sinatra'
19
+ gem.add_dependency 'commander'
20
+ gem.add_dependency 'pygments.rb'
21
+ gem.add_dependency 'nokogiri'
22
+
23
+ gem.add_development_dependency 'rspec'
24
+ gem.add_development_dependency 'rake'
25
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe "prezio convert <template> <presentation>" do
4
+ let(:template_file) { fixture_file("sample_slides.html") }
5
+ let(:presentation_file) { "/tmp/presentation.html" }
6
+
7
+ let(:content) { File.read(presentation_file) }
8
+
9
+ before do
10
+ system("rm -rf #{presentation_file}")
11
+ @status = run_prezio_convert
12
+ end
13
+
14
+ it "creates the presentation file" do
15
+ File.exists?(presentation_file).should be_true
16
+ end
17
+
18
+ it "creates a presentation that contains the original slides" do
19
+ content.should include("Include any html you like")
20
+ end
21
+
22
+ it "wraps content using DZSlides template" do
23
+ content.should include("{{{{ dzslides core")
24
+ end
25
+
26
+ it "converts code snippets" do
27
+ content.should include('class="highlight"')
28
+ end
29
+
30
+ it "returns status code 0" do
31
+ @status.should be_true
32
+ end
33
+
34
+ def fixture_file(name)
35
+ File.expand_path("../fixtures/#{name}", __FILE__)
36
+ end
37
+
38
+ def run_prezio_convert
39
+ system("./bin/prezio convert #{template_file} #{presentation_file}")
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ <title>Some title</title>
2
+
3
+ <!-- One section is one slide -->
4
+ <section>
5
+ <h1>The title</h1>
6
+ <footer>by Someone Known</footer>
7
+ </section>
8
+
9
+ <section>
10
+ <!-- Any HTML -->
11
+ <p>Include any html you like</p>
12
+ </section>
13
+
14
+ <section>
15
+ <!-- This will be highlighted -->
16
+ <code lang="ruby">
17
+ def greet(name)
18
+ println "Hello, #{name}!"
19
+ end
20
+
21
+ def foo
22
+
23
+ end
24
+ </code>
25
+ </section>
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Prezio::DZSlidesWrapper do
4
+ def wrap(html)
5
+ Prezio::DZSlidesWrapper.wrap(html)
6
+ end
7
+
8
+ it "adds the HTML5 doctype" do
9
+ wrap("the content").should include("<!DOCTYPE html>")
10
+ end
11
+
12
+ it "adds the meta tag" do
13
+ wrap("the content").should include('<meta charset="utf-8">')
14
+ end
15
+
16
+ it "adds the styles" do
17
+ wrap("the content").should include("<style>")
18
+ wrap("the content").should include(".view section")
19
+ wrap("the content").should include("</style>")
20
+ end
21
+
22
+ it "adds the JS" do
23
+ wrap("the content").should include("<script>")
24
+ wrap("the content").should include("Dz.init")
25
+ wrap("the content").should include("Dz.onkeydown")
26
+ wrap("the content").should include("</script>")
27
+ end
28
+
29
+ it "keeps the original content" do
30
+ html = "<section>hello</section>"
31
+ wrap(html).should include(html)
32
+ end
33
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Prezio::SyntaxHighlighter do
4
+ HTML = <<-HTML
5
+ <section>welcome</section>
6
+
7
+ <section>
8
+ <code lang="ruby">
9
+ def hello
10
+ puts "hello ruby"
11
+ end
12
+ </code>
13
+ </section>
14
+
15
+ <section>
16
+ <code lang="python">
17
+ def hello():
18
+ print "hello python"
19
+ </code>
20
+ </section>
21
+
22
+ <section>goodbye</section>
23
+ HTML
24
+
25
+ let(:result) { Prezio::SyntaxHighlighter.highlight(HTML) }
26
+
27
+ it "keeps the non-code sections" do
28
+ result.should include("<section>welcome</section>")
29
+ result.should include("<section>goodbye</section>")
30
+ end
31
+
32
+ it "highlighs all the code sections" do
33
+ result.should include('class="highlight"')
34
+ result.should include('hello ruby')
35
+ result.should include('hello python')
36
+ end
37
+
38
+ it "does not add body/html tags to content" do
39
+ result.should_not include('body')
40
+ result.should_not include('html')
41
+ end
42
+
43
+ it "adds the css for the highlighted code" do
44
+ result.should include('style')
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ require_relative "../lib/prezio"
2
+
3
+ RSpec.configure do |config|
4
+ config.color_enabled = true
5
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: prezio
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Pohorecki
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sinatra
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: commander
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: pygments.rb
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: nokogiri
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rake
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: HTML5 presentation generator
111
+ email:
112
+ - adam@pohorecki.pl
113
+ executables:
114
+ - prezio
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - Gemfile
120
+ - LICENSE
121
+ - README.md
122
+ - Rakefile
123
+ - bin/prezio
124
+ - lib/prezio.rb
125
+ - lib/prezio/converter.rb
126
+ - lib/prezio/dz_slides/template.html
127
+ - lib/prezio/dz_slides_wrapper.rb
128
+ - lib/prezio/octopress/highlight.html
129
+ - lib/prezio/syntax_highlighter.rb
130
+ - lib/prezio/version.rb
131
+ - prezio.gemspec
132
+ - spec/convert_spec.rb
133
+ - spec/fixtures/sample_slides.html
134
+ - spec/prezio/dz_slides_wrapper_spec.rb
135
+ - spec/prezio/syntax_highlighter_spec.rb
136
+ - spec/spec_helper.rb
137
+ homepage: http://github.com/psyho/prezio
138
+ licenses: []
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ segments:
150
+ - 0
151
+ hash: -571427853
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ segments:
159
+ - 0
160
+ hash: -571427853
161
+ requirements: []
162
+ rubyforge_project:
163
+ rubygems_version: 1.8.24
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: HTML5 presentation generator
167
+ test_files:
168
+ - spec/convert_spec.rb
169
+ - spec/fixtures/sample_slides.html
170
+ - spec/prezio/dz_slides_wrapper_spec.rb
171
+ - spec/prezio/syntax_highlighter_spec.rb
172
+ - spec/spec_helper.rb