showoff 0.12.2 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +3 -1
- data/Rakefile +27 -2
- data/bin/showoff +22 -12
- data/lib/showoff.rb +21 -43
- data/lib/showoff/version.rb +1 -1
- data/lib/showoff_utils.rb +79 -14
- data/public/css/showoff.css +12 -1
- metadata +2 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c54ccde20fbe6df23ec6b8760dc4c379fdd5e510
|
4
|
+
data.tar.gz: 1da82fd0d90fbdeffee8da521ab4fba731046672
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d3d1f9f9e699646c389383282dabb862dd7c9ae0fe681a9a63f1efc158dea921847ba10a34b415352a47e74bed93a0a040fac600e416445d2f2545d14481087
|
7
|
+
data.tar.gz: 6c100036f06dd912ba08f8eeca4670807d342103e4e9db5946fafbee629e10f9765785ef074a8aa06006c231b107d136090745ef3ed74c1fa5b34e661242621d
|
data/LICENSE
CHANGED
data/Rakefile
CHANGED
@@ -1,8 +1,33 @@
|
|
1
|
-
task default
|
1
|
+
task :default do
|
2
|
+
system("rake -T")
|
3
|
+
end
|
2
4
|
|
3
5
|
desc "Build HTML documentation"
|
4
6
|
task :doc do
|
5
|
-
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
FileUtils.rm_rf('doc')
|
10
|
+
Dir.chdir('documentation') do
|
11
|
+
system("rdoc --main -HOME.rdoc /*.rdoc --op ../doc")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Update docs for webpage"
|
16
|
+
task 'doc:website' => [:doc] do
|
17
|
+
require 'fileutils'
|
18
|
+
|
19
|
+
if system('git checkout gh-pages')
|
20
|
+
FileUtils.rm_rf('documentation')
|
21
|
+
FileUtils.mv('doc', 'documentation')
|
22
|
+
system('git add documentation')
|
23
|
+
system('git commit -m "updating docs"')
|
24
|
+
system('git checkout -')
|
25
|
+
|
26
|
+
puts "Publish updates by pushing to Github:"
|
27
|
+
puts
|
28
|
+
puts " git push upstream gh-pages"
|
29
|
+
puts
|
30
|
+
end
|
6
31
|
end
|
7
32
|
|
8
33
|
desc "Run tests"
|
data/bin/showoff
CHANGED
@@ -21,10 +21,6 @@ A web based presentation engine with awesome interaction features.
|
|
21
21
|
that are served locally for presentation via web browser. Your audience can
|
22
22
|
view presentations directly as well, and interact with you in many ways.
|
23
23
|
|
24
|
-
ShowOff can optionally use the RMagick gem for automatic image resizing
|
25
|
-
functionality. If RMagick is available, images included in your presentation
|
26
|
-
will be resized down to meet size constraints of your presentation if needed.
|
27
|
-
|
28
24
|
Showoff can optionally use the PDFKit gem to autogenerate PDF files on demand.
|
29
25
|
Viewers can access the /pdf endpoint to download a generated PDF file. This
|
30
26
|
functionality is likely to be deprecated, since it is simpler and easier to
|
@@ -36,29 +32,31 @@ desc
|
|
36
32
|
|
37
33
|
|
38
34
|
desc 'Create new showoff presentation'
|
39
|
-
arg_name 'dir_name'
|
40
35
|
long_desc 'This command helps start a new showoff presentation by setting up the proper directory structure for you. It takes the directory name you would like showoff to create for you.'
|
41
36
|
command [:create,:init] do |c|
|
42
37
|
|
43
38
|
c.desc 'Don''t create sample slides'
|
44
39
|
c.switch [:n,:nosamples]
|
45
40
|
|
46
|
-
c.desc '
|
41
|
+
c.desc 'Comma separated list of initial slide directory name(s).'
|
47
42
|
c.default_value 'one'
|
48
43
|
c.flag [:d,:slidedir]
|
49
44
|
|
50
45
|
c.action do |global_options,options,args|
|
51
|
-
|
52
|
-
ShowOffUtils.create(
|
46
|
+
dir_name = args.first || '.'
|
47
|
+
ShowOffUtils.create(dir_name,!options[:n],options[:d])
|
53
48
|
if options[:n]
|
54
|
-
puts "Add slides and update #{
|
49
|
+
puts "Add slides and update #{dir_name}/#{ShowOffUtils.presentation_config_file}"
|
50
|
+
end
|
51
|
+
if args.empty?
|
52
|
+
puts "Run 'showoff serve' to see your new slideshow"
|
53
|
+
else
|
54
|
+
puts "Run 'showoff serve' in the #{dir_name} directory to see your new slideshow"
|
55
55
|
end
|
56
|
-
puts "Run 'showoff serve' in the #{args[0]} directory to see your new slideshow"
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
desc 'Build a showoff presentation from a showoff.json
|
61
|
-
arg_name 'dir_name'
|
59
|
+
desc 'Build a showoff presentation from a showoff.json outline'
|
62
60
|
long_desc 'This command helps start a new showoff presentation by creating each slide listing in the showoff.json file.'
|
63
61
|
command [:skeleton] do |c|
|
64
62
|
|
@@ -71,6 +69,18 @@ command [:skeleton] do |c|
|
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
72
|
+
desc 'Validate the consistency of your presentation.'
|
73
|
+
long_desc 'This ensures that each file listed in showoff.json exists and validates code blocks on each slide.'
|
74
|
+
command [:validate] do |c|
|
75
|
+
|
76
|
+
c.desc 'alternate json filename'
|
77
|
+
c.flag [:f,:file]
|
78
|
+
|
79
|
+
c.action do |global_options,options,args|
|
80
|
+
ShowOffUtils.validate(options[:f])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
74
84
|
desc 'Puts your showoff presentation into a gh-pages branch'
|
75
85
|
long_desc 'Generates a static version of your presentation into your gh-pages branch for publishing to GitHub Pages'
|
76
86
|
command :github do |c|
|
data/lib/showoff.rb
CHANGED
@@ -7,27 +7,13 @@ require 'pathname'
|
|
7
7
|
require 'logger'
|
8
8
|
require 'htmlentities'
|
9
9
|
require 'sinatra-websocket'
|
10
|
+
require 'tempfile'
|
10
11
|
|
11
12
|
here = File.expand_path(File.dirname(__FILE__))
|
12
13
|
require "#{here}/showoff_utils"
|
13
14
|
require "#{here}/commandline_parser"
|
14
15
|
require "#{here}/keymap"
|
15
16
|
|
16
|
-
begin
|
17
|
-
require 'rmagick'
|
18
|
-
puts "********************************************************************************"
|
19
|
-
puts " RMagick support has been deprecated."
|
20
|
-
puts
|
21
|
-
puts "CSS auto-scaling has improved greatly, and the image manipulation should no"
|
22
|
-
puts "longer be required. If you have images that don't scale properly, then you"
|
23
|
-
puts "should write custom styles to size them appropriately."
|
24
|
-
puts
|
25
|
-
puts " RMagic support will be removed completely in the next release."
|
26
|
-
puts "********************************************************************************"
|
27
|
-
rescue LoadError
|
28
|
-
# nop
|
29
|
-
end
|
30
|
-
|
31
17
|
begin
|
32
18
|
require 'pdfkit'
|
33
19
|
rescue LoadError
|
@@ -128,6 +114,14 @@ class ShowOff < Sinatra::Application
|
|
128
114
|
settings.showoff_config['locked'] ||= Array.new
|
129
115
|
end
|
130
116
|
|
117
|
+
# default code validators
|
118
|
+
settings.showoff_config['validators'] ||= {}
|
119
|
+
settings.showoff_config['validators']['perl'] ||= 'perl -cw'
|
120
|
+
settings.showoff_config['validators']['puppet'] ||= 'puppet parser validate'
|
121
|
+
settings.showoff_config['validators']['python'] ||= 'python -m py_compile'
|
122
|
+
settings.showoff_config['validators']['ruby'] ||= 'ruby -c'
|
123
|
+
settings.showoff_config['validators']['shell'] ||= 'sh -n'
|
124
|
+
|
131
125
|
# highlightjs syntax style
|
132
126
|
@highlightStyle = settings.showoff_config['highlight'] || 'default'
|
133
127
|
|
@@ -453,7 +447,7 @@ class ShowOff < Sinatra::Application
|
|
453
447
|
end
|
454
448
|
|
455
449
|
# Load and replace any file tags
|
456
|
-
content.scan(/(~~~FILE:([
|
450
|
+
content.scan(/(~~~FILE:([^:~]*):?(.*)?~~~)/).each do |match|
|
457
451
|
# make a list of code highlighting classes to include
|
458
452
|
css = match[2].split.collect {|i| "language-#{i.downcase}" }.join(' ')
|
459
453
|
|
@@ -809,35 +803,10 @@ class ShowOff < Sinatra::Application
|
|
809
803
|
img_path = Pathname.new(File.join(slide_dir, img[:src])).cleanpath.to_path
|
810
804
|
src = "#{replacement_prefix}/#{img_path}"
|
811
805
|
img[:src] = src
|
812
|
-
|
813
|
-
# TDOD: deprecated and to be removed
|
814
|
-
w, h = get_image_size(img_path)
|
815
|
-
if w && h
|
816
|
-
img[:width] = w
|
817
|
-
img[:height] = h
|
818
|
-
end
|
819
806
|
end
|
820
807
|
doc.to_html
|
821
808
|
end
|
822
809
|
|
823
|
-
if defined?(Magick)
|
824
|
-
def get_image_size(path)
|
825
|
-
if !cached_image_size.key?(path)
|
826
|
-
img = Magick::Image.ping(path).first
|
827
|
-
# don't set a size for svgs so they can expand to fit their container
|
828
|
-
if img.mime_type == 'image/svg+xml'
|
829
|
-
cached_image_size[path] = [nil, nil]
|
830
|
-
else
|
831
|
-
cached_image_size[path] = [img.columns, img.rows]
|
832
|
-
end
|
833
|
-
end
|
834
|
-
cached_image_size[path]
|
835
|
-
end
|
836
|
-
else
|
837
|
-
def get_image_size(path)
|
838
|
-
end
|
839
|
-
end
|
840
|
-
|
841
810
|
def update_commandline_code(slide)
|
842
811
|
html = Nokogiri::HTML::DocumentFragment.parse(slide)
|
843
812
|
parser = CommandlineParser.new
|
@@ -1208,7 +1177,7 @@ class ShowOff < Sinatra::Application
|
|
1208
1177
|
end
|
1209
1178
|
|
1210
1179
|
# Load a slide file from disk, parse it and return the text of a code block by index
|
1211
|
-
def get_code_from_slide(path, index)
|
1180
|
+
def get_code_from_slide(path, index, executable=true)
|
1212
1181
|
if path =~ /^(.*)(?::)(\d+)$/
|
1213
1182
|
path = $1
|
1214
1183
|
num = $2.to_i
|
@@ -1216,6 +1185,8 @@ class ShowOff < Sinatra::Application
|
|
1216
1185
|
num = 1
|
1217
1186
|
end
|
1218
1187
|
|
1188
|
+
classes = executable ? 'code.execute' : 'code'
|
1189
|
+
|
1219
1190
|
slide = "#{path}.md"
|
1220
1191
|
return unless File.exist? slide
|
1221
1192
|
|
@@ -1227,7 +1198,14 @@ class ShowOff < Sinatra::Application
|
|
1227
1198
|
html = process_markdown(slide, content, {})
|
1228
1199
|
doc = Nokogiri::HTML::DocumentFragment.parse(html)
|
1229
1200
|
|
1230
|
-
|
1201
|
+
if index == 'all'
|
1202
|
+
doc.css(classes).collect do |code|
|
1203
|
+
lang = code.attr('class') =~ /language-(\S*)/ ? $1 : nil
|
1204
|
+
[lang, code.text]
|
1205
|
+
end
|
1206
|
+
else
|
1207
|
+
doc.css(classes)[index.to_i].text rescue 'Invalid code block index'
|
1208
|
+
end
|
1231
1209
|
end
|
1232
1210
|
|
1233
1211
|
# Basic auth boilerplate
|
data/lib/showoff/version.rb
CHANGED
data/lib/showoff_utils.rb
CHANGED
@@ -31,19 +31,26 @@ class ShowOffUtils
|
|
31
31
|
@presentation_config_file = filename
|
32
32
|
end
|
33
33
|
|
34
|
-
def self.create(dirname,create_samples,
|
34
|
+
def self.create(dirname,create_samples,dirs='one')
|
35
35
|
FileUtils.mkdir_p(dirname)
|
36
36
|
Dir.chdir(dirname) do
|
37
|
-
|
38
|
-
# create section
|
39
|
-
FileUtils.mkdir_p(dir)
|
37
|
+
dirs = dirs.split(',')
|
40
38
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
if create_samples
|
40
|
+
dirs.each do |dir|
|
41
|
+
# create section
|
42
|
+
FileUtils.mkdir_p(dir)
|
43
|
+
|
44
|
+
# create markdown file
|
45
|
+
File.open("#{dir}/00_section.md", 'w+') do |f|
|
46
|
+
f.puts make_slide("Section Header", "center subsection")
|
47
|
+
end
|
48
|
+
File.open("#{dir}/01_slide.md", 'w+') do |f|
|
49
|
+
f.puts make_slide("My Presentation")
|
50
|
+
end
|
51
|
+
File.open("#{dir}/02_slide.md", 'w+') do |f|
|
52
|
+
f.puts make_slide("Bullet Points","bullets incremental",["first point","second point","third point"])
|
53
|
+
end
|
47
54
|
end
|
48
55
|
end
|
49
56
|
|
@@ -53,7 +60,8 @@ class ShowOffUtils
|
|
53
60
|
|
54
61
|
# create showoff.json
|
55
62
|
File.open(ShowOffUtils.presentation_config_file, 'w+') do |f|
|
56
|
-
|
63
|
+
sections = dirs.collect {|dir| {"section" => dir} }
|
64
|
+
f.puts JSON.pretty_generate({ "name" => "My Preso", "sections" => sections })
|
57
65
|
end
|
58
66
|
end
|
59
67
|
end
|
@@ -76,7 +84,12 @@ class ShowOffUtils
|
|
76
84
|
FileUtils.mkdir_p File.dirname(filename)
|
77
85
|
|
78
86
|
File.open(filename, 'w+') do |f|
|
79
|
-
|
87
|
+
if filename =~ /section/i
|
88
|
+
# kind of looks like a section slide
|
89
|
+
f.puts make_slide("#{filename.sub(/\.md$/, '')}", "center subsection")
|
90
|
+
else
|
91
|
+
f.puts make_slide("#{filename.sub(/\.md$/, '')}")
|
92
|
+
end
|
80
93
|
end
|
81
94
|
else
|
82
95
|
FileUtils.mkdir_p filename
|
@@ -84,6 +97,55 @@ class ShowOffUtils
|
|
84
97
|
end
|
85
98
|
end
|
86
99
|
|
100
|
+
def self.validate(config)
|
101
|
+
showoff = ShowOff.new!(:pres_file => config)
|
102
|
+
validators = showoff.settings.showoff_config['validators'] || {}
|
103
|
+
files = []
|
104
|
+
errors = []
|
105
|
+
|
106
|
+
# get a list of actual filenames
|
107
|
+
self.showoff_sections('.').each do |section|
|
108
|
+
if File.directory?(section)
|
109
|
+
files << showoff.load_section_files(section)
|
110
|
+
else
|
111
|
+
files << section
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
files.flatten!
|
116
|
+
files.each do |filename|
|
117
|
+
unless File.exist? filename
|
118
|
+
errors << "Missing path: #{filename}"
|
119
|
+
next
|
120
|
+
end
|
121
|
+
|
122
|
+
if filename.downcase.end_with? '.md'
|
123
|
+
print '.'
|
124
|
+
showoff.get_code_from_slide(filename.sub('.md',''), 'all', false).each_with_index do |block, index|
|
125
|
+
lang, code = block
|
126
|
+
validator = validators[lang]
|
127
|
+
if validator
|
128
|
+
# write out a tempfile because many validators require files to with
|
129
|
+
Tempfile.open('showoff-validation') do |f|
|
130
|
+
File.write(f.path, code)
|
131
|
+
unless system("#{validator} #{f.path}", :out => File::NULL, :err => File::NULL)
|
132
|
+
print 'F'
|
133
|
+
errors << "Invalid #{lang} code on #{filename} [#{index}]"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
puts
|
142
|
+
puts "Found #{errors.size} errors."
|
143
|
+
unless errors.empty?
|
144
|
+
errors.each { |err| puts " * #{err}" }
|
145
|
+
exit!
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
87
149
|
HEROKU_GEMS_FILE = '.gems'
|
88
150
|
HEROKU_BUNDLER_GEMS_FILE = 'Gemfile'
|
89
151
|
HEROKU_CONFIG_FILE = 'config.ru'
|
@@ -263,9 +325,12 @@ class ShowOffUtils
|
|
263
325
|
# name a slide as the last slide in the dir.
|
264
326
|
def self.find_next_number(slide_dir)
|
265
327
|
slide_dir ||= '.'
|
266
|
-
|
328
|
+
max = Dir.glob("#{slide_dir}/*.md").collect do |f|
|
329
|
+
next unless f =~ /^#{slide_dir}\/(\d+)/
|
330
|
+
$1.to_i
|
331
|
+
end.compact.max || 0
|
267
332
|
|
268
|
-
sprintf("%02d",
|
333
|
+
sprintf("%02d", max+1)
|
269
334
|
end
|
270
335
|
|
271
336
|
def self.determine_title(title,slide_name,code)
|
data/public/css/showoff.css
CHANGED
@@ -47,6 +47,10 @@ pre code {
|
|
47
47
|
overflow: hidden;
|
48
48
|
}
|
49
49
|
|
50
|
+
body#download {
|
51
|
+
overflow: auto;
|
52
|
+
}
|
53
|
+
|
50
54
|
#preso,
|
51
55
|
.slide {
|
52
56
|
background: #fff;
|
@@ -842,7 +846,8 @@ form .element {
|
|
842
846
|
.callout.warning,
|
843
847
|
.callout.question,
|
844
848
|
.callout.exercise,
|
845
|
-
.callout.stop
|
849
|
+
.callout.stop,
|
850
|
+
.callout.thumbsup {
|
846
851
|
padding-left: 3em;
|
847
852
|
}
|
848
853
|
|
@@ -851,6 +856,7 @@ form .element {
|
|
851
856
|
.callout.question:before { content: "\f059"; } /* fa-question-circle */
|
852
857
|
.callout.exercise:before { content: "\f41b"; } /* fa-pencil-square */
|
853
858
|
.callout.stop:before { content: "\f05e"; } /* fa-ban */
|
859
|
+
.callout.thumbsup:before { content: "\f164"; } /* fa-thumbs-up */
|
854
860
|
|
855
861
|
/**********************
|
856
862
|
*** end callouts ***
|
@@ -957,6 +963,11 @@ form .element {
|
|
957
963
|
border-top: 2px dashed #999;
|
958
964
|
}
|
959
965
|
|
966
|
+
.notes-section .callout {
|
967
|
+
margin-right: 1em;
|
968
|
+
margin-left: 1em;
|
969
|
+
}
|
970
|
+
|
960
971
|
.notes-section.notes .personal {
|
961
972
|
float: right;
|
962
973
|
border-left: 2px solid #999;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: showoff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Chacon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -353,10 +353,6 @@ post_install_message: |2+
|
|
353
353
|
means that if you've created your own custom styles, that you'll need to
|
354
354
|
refactor them. We do hope you find the new styles simpler and better looking.
|
355
355
|
|
356
|
-
RMagick will be completely removed in the next major release. Pleas migrate
|
357
|
-
away from it now. Browsers can autoscale images on demand pretty well now,
|
358
|
-
so you probably won't miss it much.
|
359
|
-
|
360
356
|
Showoff can optionally use the PDFKit gem to build PDF files using the
|
361
357
|
`showoff pdf` command. If you'd like your audience to download the PDF,
|
362
358
|
place it in `_files/share`.
|