showoff 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +66 -17
- data/lib/showoff.rb +20 -17
- data/public/css/onepage.css +1 -1
- data/public/css/pdf.css +1 -1
- data/public/css/reset.css +53 -0
- data/public/css/showoff.css +17 -27
- data/public/js/jquery.batchImageLoad.js +56 -0
- data/public/js/jquery.cycle.all.js +1284 -0
- data/public/js/onepage.js +1 -6
- data/public/js/showoff.js +66 -29
- data/views/index.erb +6 -3
- data/views/onepage.erb +2 -2
- metadata +6 -3
data/README.txt
CHANGED
@@ -2,13 +2,13 @@ ShowOff Presentation Software
|
|
2
2
|
=============================
|
3
3
|
|
4
4
|
ShowOff is a Sinatra web app that reads simple configuration files for a
|
5
|
-
presentation. It is sort of like a Keynote web app engine - think S5 +
|
6
|
-
Slidedown. I am using it to do all my talks in 2010, because I have a deep
|
5
|
+
presentation. It is sort of like a Keynote web app engine - think S5 +
|
6
|
+
Slidedown. I am using it to do all my talks in 2010, because I have a deep
|
7
7
|
hatred in my heart for Keynote and yet it is by far the best in the field.
|
8
8
|
|
9
9
|
The idea is that you setup your markdown slide files in section subdirectories
|
10
10
|
and then startup the showoff server in that directory. It will read in your
|
11
|
-
showoff.json file for which sections go in which order and then will give
|
11
|
+
showoff.json file for which sections go in which order and then will give
|
12
12
|
you a URL to present from.
|
13
13
|
|
14
14
|
It can:
|
@@ -20,10 +20,10 @@ It can:
|
|
20
20
|
* re-enact command line interactions
|
21
21
|
* call up a menu of sections/slides at any time to jump around
|
22
22
|
* execute javascript or ruby live and display results
|
23
|
+
* do simple transitions (instant, fade, slide in)
|
23
24
|
|
24
25
|
It might will can:
|
25
26
|
|
26
|
-
* do simple transitions (instant, fade, slide in)
|
27
27
|
* show a timer - elapsed / remaining
|
28
28
|
* perform simple animations of images moving between keyframes
|
29
29
|
* show syncronized, hidden notes on another browser (like an iphone)
|
@@ -48,7 +48,7 @@ it has a showoff.json file and a number of sections (subdirectories) with markdo
|
|
48
48
|
$ cd (showoff-repo)
|
49
49
|
$ showoff serve
|
50
50
|
|
51
|
-
If you run 'showoff' in the ShowOff directory itself, it will show an example
|
51
|
+
If you run 'showoff' in the ShowOff directory itself, it will show an example
|
52
52
|
presentation from the 'example' subdirectory, so you can see what it's like.
|
53
53
|
|
54
54
|
Slide Format
|
@@ -60,7 +60,7 @@ your showoff.json file for any markdown files (.md). Each markdown file can
|
|
60
60
|
have any number of slides in it, seperating each slide with the '!SLIDE'
|
61
61
|
keyword and optional slide styles.
|
62
62
|
|
63
|
-
For example, if you run 'showoff create my_new_pres' it will create a new
|
63
|
+
For example, if you run 'showoff create my_new_pres' it will create a new
|
64
64
|
starter presentation for you with one .md file at one/slide.md which will have
|
65
65
|
the following contents:
|
66
66
|
|
@@ -68,7 +68,7 @@ the following contents:
|
|
68
68
|
|
69
69
|
# My Presentation #
|
70
70
|
|
71
|
-
!SLIDE bullets incremental
|
71
|
+
!SLIDE bullets incremental transition=fade
|
72
72
|
|
73
73
|
# Bullet Points #
|
74
74
|
|
@@ -76,17 +76,17 @@ the following contents:
|
|
76
76
|
* second point
|
77
77
|
* third point
|
78
78
|
|
79
|
-
That represents two slides,
|
80
|
-
|
81
|
-
ShowOff to see those slides, your
|
82
|
-
like this:
|
79
|
+
That represents two slides, the first contains just a large title, and the
|
80
|
+
second is faded into view showing the title and three bullets that are then
|
81
|
+
incrementally shown. In order for ShowOff to see those slides, your
|
82
|
+
showoff.json file needs to look something like this:
|
83
83
|
|
84
|
-
[
|
85
|
-
{"section":"one"}
|
84
|
+
[
|
85
|
+
{"section":"one"}
|
86
86
|
]
|
87
87
|
|
88
|
-
If you have multiple sections in your talk, you can make this json array
|
89
|
-
include all the sections you want to show in which order you want to show
|
88
|
+
If you have multiple sections in your talk, you can make this json array
|
89
|
+
include all the sections you want to show in which order you want to show
|
90
90
|
them.
|
91
91
|
|
92
92
|
Some useful styles for each slide are:
|
@@ -96,7 +96,7 @@ Some useful styles for each slide are:
|
|
96
96
|
* smbullets - sizes and seperates more bullets (smaller, closer together)
|
97
97
|
* subsection - creates a different background for titles
|
98
98
|
* command - monospaces h1 title slides
|
99
|
-
* commandline - for pasted commandline sections
|
99
|
+
* commandline - for pasted commandline sections
|
100
100
|
(needs leading '$' for commands, then output on subsequent lines)
|
101
101
|
* code - monospaces everything on the slide
|
102
102
|
* incremental - can be used with 'bullets' and 'commandline' styles,
|
@@ -108,6 +108,43 @@ Some useful styles for each slide are:
|
|
108
108
|
|
109
109
|
Check out the example directory included to see examples of most of these.
|
110
110
|
|
111
|
+
Transitions can be supplied through the use of transition=tname on the !SLIDE
|
112
|
+
definition, where tname is one of the following supported transitions:
|
113
|
+
|
114
|
+
* blindX
|
115
|
+
* blindY
|
116
|
+
* blindZ
|
117
|
+
* cover
|
118
|
+
* curtainX
|
119
|
+
* curtainY
|
120
|
+
* fade
|
121
|
+
* fadeZoom
|
122
|
+
* growX
|
123
|
+
* growY
|
124
|
+
* none (this is the default)
|
125
|
+
* scrollUp
|
126
|
+
* scrollDown
|
127
|
+
* scrollLeft
|
128
|
+
* scrollRight
|
129
|
+
* scrollHorz
|
130
|
+
* scrollVert
|
131
|
+
* shuffle
|
132
|
+
* slideX
|
133
|
+
* slideY
|
134
|
+
* toss
|
135
|
+
* turnUp
|
136
|
+
* turnDown
|
137
|
+
* turnLeft
|
138
|
+
* turnRight
|
139
|
+
* uncover
|
140
|
+
* wipe
|
141
|
+
* zoom
|
142
|
+
|
143
|
+
The transitions are provided by jQuery Cycle plugin. See
|
144
|
+
http://www.malsup.com/jquery/cycle/browser.html to view the effects and
|
145
|
+
http://www.malsup.com/jquery/cycle/adv2.html for how to add
|
146
|
+
custom effects.
|
147
|
+
|
111
148
|
You can manage the presentation with the following keys:
|
112
149
|
|
113
150
|
* space, cursor right: next slide
|
@@ -115,7 +152,7 @@ You can manage the presentation with the following keys:
|
|
115
152
|
* d: debug mode
|
116
153
|
* c: table of contents (vi)
|
117
154
|
* f: toggle footer
|
118
|
-
* z: toggle help
|
155
|
+
* z: toggle help
|
119
156
|
|
120
157
|
Real World Usage
|
121
158
|
====================
|
@@ -134,6 +171,18 @@ So far, ShowOff has been used in the following presentations:
|
|
134
171
|
* LRUG's February meeting - Showing Off with Ruby - Joel Chippindale
|
135
172
|
http://github.com/mocoso/showing-off-with-ruby
|
136
173
|
|
174
|
+
* PyCon 2010 - Hg and Git; Can't we all just get along? - Scott Chacon
|
175
|
+
http://github.com/schacon/pycon-hg-git
|
176
|
+
|
177
|
+
* PdxJs Tech Talk - Asynchronous Coding For My Tiny Ruby Brain - Rick Olson
|
178
|
+
http://github.com/technoweenie/pdxjs-twitter-node
|
179
|
+
|
180
|
+
* RORO Perth Talk - Rails 3; A Brief Introduction — Darcy Laycock
|
181
|
+
http://github.com/Sutto/roro-perth-rails-3
|
182
|
+
|
183
|
+
* PDXRB Tech Talk - Here's Sinatra - Jesse Cooke
|
184
|
+
http://github.com/jc00ke/pdxrb_sinatra
|
185
|
+
|
137
186
|
If you use it for something, please let me know so I can add it.
|
138
187
|
|
139
188
|
Future Plans
|
data/lib/showoff.rb
CHANGED
@@ -3,13 +3,7 @@ require 'sinatra/base'
|
|
3
3
|
require 'json'
|
4
4
|
require 'nokogiri'
|
5
5
|
require 'showoff_utils'
|
6
|
-
|
7
|
-
begin
|
8
|
-
require 'prawn'
|
9
|
-
require 'princely'
|
10
|
-
rescue LoadError
|
11
|
-
puts 'pdf generation disabled - install prawn'
|
12
|
-
end
|
6
|
+
require 'princely'
|
13
7
|
|
14
8
|
begin
|
15
9
|
require 'rdiscount'
|
@@ -52,7 +46,7 @@ class ShowOff < Sinatra::Application
|
|
52
46
|
Dir.glob("#{options.pres_dir}/*.js").map { |path| File.basename(path) }
|
53
47
|
end
|
54
48
|
|
55
|
-
def process_markdown(name, content
|
49
|
+
def process_markdown(name, content)
|
56
50
|
slides = content.split(/^!SLIDE/)
|
57
51
|
slides.delete('')
|
58
52
|
final = ''
|
@@ -61,21 +55,30 @@ class ShowOff < Sinatra::Application
|
|
61
55
|
end
|
62
56
|
slides.each do |slide|
|
63
57
|
md = ''
|
58
|
+
# extract content classes
|
64
59
|
lines = slide.split("\n")
|
65
|
-
|
60
|
+
content_classes = lines.shift.split
|
66
61
|
slide = lines.join("\n")
|
67
|
-
|
62
|
+
# add content class too
|
63
|
+
content_classes.unshift "content"
|
64
|
+
# extract transition, defaulting to none
|
65
|
+
transition = 'none'
|
66
|
+
content_classes.delete_if { |x| x =~ /^transition=(.+)/ && transition = $1 }
|
67
|
+
puts "classes: #{content_classes.inspect}"
|
68
|
+
puts "transition: #{transition}"
|
69
|
+
# create html
|
70
|
+
md += "<div class=\"slide\" data-transition=\"#{transition}\">"
|
68
71
|
if seq
|
69
|
-
md += "<div class=\"
|
72
|
+
md += "<div class=\"#{content_classes.join(' ')}\" ref=\"#{name}/#{seq.to_s}\">\n"
|
70
73
|
seq += 1
|
71
74
|
else
|
72
|
-
md += "<div class=\"
|
75
|
+
md += "<div class=\"#{content_classes.join(' ')}\" ref=\"#{name}\">\n"
|
73
76
|
end
|
74
77
|
sl = Markdown.new(slide).to_html
|
75
78
|
sl = update_image_paths(name, sl)
|
76
79
|
md += sl
|
77
80
|
md += "</div>\n"
|
78
|
-
md += "</div>\n"
|
81
|
+
md += "</div>\n"
|
79
82
|
final += update_commandline_code(md)
|
80
83
|
end
|
81
84
|
final
|
@@ -124,7 +127,7 @@ class ShowOff < Sinatra::Application
|
|
124
127
|
html.root.to_s
|
125
128
|
end
|
126
129
|
|
127
|
-
def get_slides_html
|
130
|
+
def get_slides_html
|
128
131
|
index = File.join(options.pres_dir, 'showoff.json')
|
129
132
|
files = []
|
130
133
|
if File.exists?(index)
|
@@ -138,7 +141,7 @@ class ShowOff < Sinatra::Application
|
|
138
141
|
data = ''
|
139
142
|
files.each do |f|
|
140
143
|
fname = f.gsub(options.pres_dir + '/', '').gsub('.md', '')
|
141
|
-
data += process_markdown(fname, File.read(f)
|
144
|
+
data += process_markdown(fname, File.read(f))
|
142
145
|
end
|
143
146
|
end
|
144
147
|
data
|
@@ -189,12 +192,12 @@ class ShowOff < Sinatra::Application
|
|
189
192
|
end
|
190
193
|
|
191
194
|
get '/onepage' do
|
192
|
-
@slides = get_slides_html
|
195
|
+
@slides = get_slides_html
|
193
196
|
erb :onepage
|
194
197
|
end
|
195
198
|
|
196
199
|
get '/pdf' do
|
197
|
-
@slides = get_slides_html
|
200
|
+
@slides = get_slides_html
|
198
201
|
@no_js = true
|
199
202
|
html = erb :onepage
|
200
203
|
p = Princely.new
|
data/public/css/onepage.css
CHANGED
data/public/css/pdf.css
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
/* http://meyerweb.com/eric/tools/css/reset/ */
|
2
|
+
/* v1.0 | 20080212 */
|
3
|
+
|
4
|
+
html, body, div, span, applet, object, iframe,
|
5
|
+
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
6
|
+
a, abbr, acronym, address, big, cite, code,
|
7
|
+
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
8
|
+
small, strike, strong, sub, sup, tt, var,
|
9
|
+
b, u, i, center,
|
10
|
+
dl, dt, dd, ol, ul, li,
|
11
|
+
fieldset, form, label, legend,
|
12
|
+
table, caption, tbody, tfoot, thead, tr, th, td {
|
13
|
+
margin: 0;
|
14
|
+
padding: 0;
|
15
|
+
border: 0;
|
16
|
+
outline: 0;
|
17
|
+
font-size: 100%;
|
18
|
+
vertical-align: baseline;
|
19
|
+
background: transparent;
|
20
|
+
}
|
21
|
+
body {
|
22
|
+
line-height: 1;
|
23
|
+
}
|
24
|
+
ol, ul {
|
25
|
+
list-style: none;
|
26
|
+
}
|
27
|
+
blockquote, q {
|
28
|
+
quotes: none;
|
29
|
+
}
|
30
|
+
blockquote:before, blockquote:after,
|
31
|
+
q:before, q:after {
|
32
|
+
content: '';
|
33
|
+
content: none;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* remember to define focus styles! */
|
37
|
+
:focus {
|
38
|
+
outline: 0;
|
39
|
+
}
|
40
|
+
|
41
|
+
/* remember to highlight inserts somehow! */
|
42
|
+
ins {
|
43
|
+
text-decoration: none;
|
44
|
+
}
|
45
|
+
del {
|
46
|
+
text-decoration: line-through;
|
47
|
+
}
|
48
|
+
|
49
|
+
/* tables still need 'cellspacing="0"' in the markup */
|
50
|
+
table {
|
51
|
+
border-collapse: collapse;
|
52
|
+
border-spacing: 0;
|
53
|
+
}
|
data/public/css/showoff.css
CHANGED
@@ -1,33 +1,25 @@
|
|
1
1
|
body {
|
2
2
|
font-family: "Gill Sans", Helvetica, Arial, sans-serif;
|
3
|
-
padding: 0;
|
4
|
-
margin: 0;
|
5
|
-
border: 0;
|
6
3
|
}
|
7
4
|
|
8
|
-
#preso {
|
9
|
-
|
10
|
-
padding: 0;
|
5
|
+
#preso, .slide {
|
6
|
+
background: #fff;
|
11
7
|
width: 1020px;
|
12
8
|
height: 740px;
|
13
|
-
margin-left:auto;
|
9
|
+
margin-left:auto;
|
14
10
|
margin-right:auto;
|
15
11
|
overflow:hidden;
|
16
12
|
}
|
17
|
-
|
13
|
+
|
14
|
+
#footer {
|
18
15
|
background: #eee;
|
19
|
-
margin: 0;
|
20
16
|
padding: 2px;
|
21
17
|
width: 1010px;
|
22
18
|
height: 20px;
|
23
|
-
margin-left:auto;
|
19
|
+
margin-left:auto;
|
24
20
|
margin-right:auto;
|
25
21
|
}
|
26
22
|
|
27
|
-
.slide {
|
28
|
-
border: 1px solid #fff;
|
29
|
-
}
|
30
|
-
|
31
23
|
.center img {
|
32
24
|
display:block;
|
33
25
|
margin-left:auto;
|
@@ -35,13 +27,7 @@ body {
|
|
35
27
|
}
|
36
28
|
|
37
29
|
.bullets ul {
|
38
|
-
display: block;
|
39
|
-
height: 600px;
|
40
30
|
font-size: 3em;
|
41
|
-
list-style: none;
|
42
|
-
margin-left: 0;
|
43
|
-
padding-left: 1em;
|
44
|
-
text-indent: -1em;
|
45
31
|
}
|
46
32
|
.bullets ul li {
|
47
33
|
text-align: center;
|
@@ -49,13 +35,7 @@ body {
|
|
49
35
|
}
|
50
36
|
|
51
37
|
.smbullets ul {
|
52
|
-
display: block;
|
53
|
-
height: 600px;
|
54
38
|
font-size: 2em;
|
55
|
-
list-style: none;
|
56
|
-
margin-left: 0;
|
57
|
-
padding-left: 1em;
|
58
|
-
text-indent: -1em;
|
59
39
|
}
|
60
40
|
.smbullets ul li {
|
61
41
|
text-align: center;
|
@@ -102,9 +82,14 @@ h1 { font-size: 5em; font-weight: normal; text-align: center;}
|
|
102
82
|
h2 { font-size: 3em; font-weight: normal; text-align: center; }
|
103
83
|
h3 { font-size: 2em; font-weight: normal; text-align: center; }
|
104
84
|
|
85
|
+
h1, h2, h3 {
|
86
|
+
margin: 0.5em 0;
|
87
|
+
}
|
88
|
+
|
105
89
|
pre { margin-left: 40px; font-size: 2.8em; }
|
106
90
|
|
107
91
|
.hidden { position:absolute; top:0; left:-9999px; width:1px; height:1px; overflow:hidden; }
|
92
|
+
.offscreen { position:absolute; top:0; left:-9999px; overflow:hidden; }
|
108
93
|
#debugInfo { margin-left: 30px; }
|
109
94
|
|
110
95
|
#help {
|
@@ -112,6 +97,7 @@ pre { margin-left: 40px; font-size: 2.8em; }
|
|
112
97
|
position: absolute;
|
113
98
|
right: 80px;
|
114
99
|
display: none;
|
100
|
+
z-index: 2147483647; //max, see http://www.puidokas.com/max-z-index/
|
115
101
|
}
|
116
102
|
#help table tr td.key {
|
117
103
|
text-align: right;
|
@@ -120,6 +106,10 @@ pre { margin-left: 40px; font-size: 2.8em; }
|
|
120
106
|
font-weight: bold;
|
121
107
|
}
|
122
108
|
|
109
|
+
.fg-menu-container {
|
110
|
+
z-index: 2147483647; //max, see http://www.puidokas.com/max-z-index/
|
111
|
+
}
|
112
|
+
|
123
113
|
.fg-button { clear:left; margin:0 4px 40px 20px; padding: .4em 1em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
|
124
114
|
.fg-button .ui-icon { position: absolute; top: 50%; margin-top: -8px; left: 50%; margin-left: -8px; }
|
125
115
|
a.fg-button { float:left; }
|
@@ -190,7 +180,7 @@ a.fg-button { float:left; }
|
|
190
180
|
.code .vi { color: #008080 } /* Name.Variable.Instance */
|
191
181
|
.code .il { color: #009999 } /* Literal.Number.Integer.Long */
|
192
182
|
|
193
|
-
.results {
|
183
|
+
.results {
|
194
184
|
background-color:#002200;
|
195
185
|
color:#00AA00;
|
196
186
|
font-size:2em;
|
@@ -0,0 +1,56 @@
|
|
1
|
+
/**
|
2
|
+
* Plugin which is applied on a list of img objects and calls
|
3
|
+
* the specified callback function, only when all of them are loaded (or errored).
|
4
|
+
* @author: H. Yankov (hristo.yankov at gmail dot com)
|
5
|
+
* @version: 1.0.0 (Feb/22/2010)
|
6
|
+
* http://yankov.us
|
7
|
+
*/
|
8
|
+
|
9
|
+
(function($) {
|
10
|
+
$.fn.batchImageLoad = function(options) {
|
11
|
+
var images = $(this);
|
12
|
+
var originalTotalImagesCount = images.size();
|
13
|
+
var totalImagesCount = originalTotalImagesCount;
|
14
|
+
var elementsLoaded = 0;
|
15
|
+
|
16
|
+
// Init
|
17
|
+
$.fn.batchImageLoad.defaults = {
|
18
|
+
loadingCompleteCallback: null,
|
19
|
+
imageLoadedCallback: null
|
20
|
+
}
|
21
|
+
var opts = $.extend({}, $.fn.batchImageLoad.defaults, options);
|
22
|
+
|
23
|
+
// Start
|
24
|
+
images.each(function() {
|
25
|
+
// The image has already been loaded (cached)
|
26
|
+
if ($(this)[0].complete) {
|
27
|
+
totalImagesCount--;
|
28
|
+
if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
|
29
|
+
// The image is loading, so attach the listener
|
30
|
+
} else {
|
31
|
+
$(this).load(function() {
|
32
|
+
elementsLoaded++;
|
33
|
+
|
34
|
+
if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
|
35
|
+
|
36
|
+
// An image has been loaded
|
37
|
+
if (elementsLoaded >= totalImagesCount)
|
38
|
+
if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
|
39
|
+
});
|
40
|
+
$(this).error(function() {
|
41
|
+
elementsLoaded++;
|
42
|
+
|
43
|
+
if (opts.imageLoadedCallback) opts.imageLoadedCallback(elementsLoaded, originalTotalImagesCount);
|
44
|
+
|
45
|
+
// The image has errored
|
46
|
+
if (elementsLoaded >= totalImagesCount)
|
47
|
+
if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
|
48
|
+
});
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
// There are no unloaded images
|
53
|
+
if (totalImagesCount <= 0)
|
54
|
+
if (opts.loadingCompleteCallback) opts.loadingCompleteCallback();
|
55
|
+
};
|
56
|
+
})(jQuery);
|