mg_showoff 0.5.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.
- data/LICENSE +20 -0
- data/README.rdoc +532 -0
- data/Rakefile +7 -0
- data/bin/showoff +145 -0
- data/lib/commandline_parser.rb +67 -0
- data/lib/princely.rb +84 -0
- data/lib/showoff.rb +452 -0
- data/lib/showoff_utils.rb +369 -0
- data/public/css/fg.menu.css +114 -0
- data/public/css/onepage.css +60 -0
- data/public/css/pdf.css +12 -0
- data/public/css/reset.css +53 -0
- data/public/css/sh_style.css +66 -0
- data/public/css/showoff.css +361 -0
- data/public/css/spinner_bar.gif +0 -0
- data/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
- data/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
- data/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
- data/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
- data/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
- data/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
- data/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
- data/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
- data/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
- data/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
- data/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
- data/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
- data/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
- data/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
- data/public/css/theme/ui.accordion.css +9 -0
- data/public/css/theme/ui.all.css +2 -0
- data/public/css/theme/ui.base.css +9 -0
- data/public/css/theme/ui.core.css +37 -0
- data/public/css/theme/ui.datepicker.css +62 -0
- data/public/css/theme/ui.dialog.css +13 -0
- data/public/css/theme/ui.progressbar.css +4 -0
- data/public/css/theme/ui.resizable.css +13 -0
- data/public/css/theme/ui.slider.css +17 -0
- data/public/css/theme/ui.tabs.css +9 -0
- data/public/css/theme/ui.theme.css +245 -0
- data/public/favicon.ico +0 -0
- data/public/js/core.js +79 -0
- data/public/js/fg.menu.js +645 -0
- data/public/js/jTypeWriter.js +26 -0
- data/public/js/jquery-1.4.2.min.js +154 -0
- data/public/js/jquery-print.js +109 -0
- data/public/js/jquery.batchImageLoad.js +56 -0
- data/public/js/jquery.cookie.js +96 -0
- data/public/js/jquery.cycle.all.js +1284 -0
- data/public/js/jquery.doubletap-0.1.js +105 -0
- data/public/js/jquery.uuid.js +24 -0
- data/public/js/jquery.ws-0.3pre.js +201 -0
- data/public/js/onepage.js +5 -0
- data/public/js/sh_lang/sh_bison.min.js +1 -0
- data/public/js/sh_lang/sh_c.min.js +1 -0
- data/public/js/sh_lang/sh_caml.min.js +1 -0
- data/public/js/sh_lang/sh_changelog.min.js +1 -0
- data/public/js/sh_lang/sh_cpp.min.js +1 -0
- data/public/js/sh_lang/sh_csharp.min.js +1 -0
- data/public/js/sh_lang/sh_css.min.js +1 -0
- data/public/js/sh_lang/sh_cucumber.min.js +2 -0
- data/public/js/sh_lang/sh_desktop.min.js +1 -0
- data/public/js/sh_lang/sh_diff.min.js +1 -0
- data/public/js/sh_lang/sh_flex.min.js +1 -0
- data/public/js/sh_lang/sh_glsl.min.js +1 -0
- data/public/js/sh_lang/sh_haxe.min.js +1 -0
- data/public/js/sh_lang/sh_html.min.js +1 -0
- data/public/js/sh_lang/sh_java.min.js +1 -0
- data/public/js/sh_lang/sh_javascript.min.js +1 -0
- data/public/js/sh_lang/sh_javascript_dom.min.js +1 -0
- data/public/js/sh_lang/sh_latex.min.js +1 -0
- data/public/js/sh_lang/sh_ldap.min.js +1 -0
- data/public/js/sh_lang/sh_log.min.js +1 -0
- data/public/js/sh_lang/sh_lsm.min.js +1 -0
- data/public/js/sh_lang/sh_m4.min.js +1 -0
- data/public/js/sh_lang/sh_makefile.min.js +1 -0
- data/public/js/sh_lang/sh_oracle.min.js +1 -0
- data/public/js/sh_lang/sh_pascal.min.js +1 -0
- data/public/js/sh_lang/sh_perl.min.js +1 -0
- data/public/js/sh_lang/sh_php.min.js +1 -0
- data/public/js/sh_lang/sh_prolog.min.js +1 -0
- data/public/js/sh_lang/sh_properties.min.js +1 -0
- data/public/js/sh_lang/sh_python.min.js +1 -0
- data/public/js/sh_lang/sh_ruby.min.js +1 -0
- data/public/js/sh_lang/sh_scala.min.js +1 -0
- data/public/js/sh_lang/sh_sh.min.js +1 -0
- data/public/js/sh_lang/sh_slang.min.js +1 -0
- data/public/js/sh_lang/sh_sml.min.js +1 -0
- data/public/js/sh_lang/sh_spec.min.js +1 -0
- data/public/js/sh_lang/sh_sql.min.js +1 -0
- data/public/js/sh_lang/sh_tcl.min.js +1 -0
- data/public/js/sh_lang/sh_xml.min.js +1 -0
- data/public/js/sh_lang/sh_xorg.min.js +1 -0
- data/public/js/sh_main.min.js +4 -0
- data/public/js/showoff.js +623 -0
- data/public/js/showoffcore.js +13 -0
- data/views/index.erb +85 -0
- data/views/onepage.erb +35 -0
- metadata +227 -0
data/lib/showoff.rb
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'sinatra/base'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'nokogiri'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'logger'
|
|
7
|
+
|
|
8
|
+
here = File.expand_path(File.dirname(__FILE__))
|
|
9
|
+
require "#{here}/showoff_utils"
|
|
10
|
+
require "#{here}/princely"
|
|
11
|
+
require "#{here}/commandline_parser"
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
require 'RMagick'
|
|
15
|
+
rescue LoadError
|
|
16
|
+
$stderr.puts 'image sizing disabled - install rmagick'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
require 'pdfkit'
|
|
21
|
+
rescue LoadError
|
|
22
|
+
$stderr.puts 'pdf generation disabled - install pdfkit'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
require 'rdiscount'
|
|
27
|
+
rescue LoadError
|
|
28
|
+
require 'bluecloth'
|
|
29
|
+
Object.send(:remove_const,:Markdown)
|
|
30
|
+
Markdown = BlueCloth
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class ShowOff < Sinatra::Application
|
|
34
|
+
|
|
35
|
+
Version = VERSION = '0.5.1'
|
|
36
|
+
|
|
37
|
+
attr_reader :cached_image_size
|
|
38
|
+
|
|
39
|
+
set :views, File.dirname(__FILE__) + '/../views'
|
|
40
|
+
set :public, File.dirname(__FILE__) + '/../public'
|
|
41
|
+
|
|
42
|
+
def initialize(app=nil)
|
|
43
|
+
super(app)
|
|
44
|
+
@logger = Logger.new(STDOUT)
|
|
45
|
+
@logger.formatter = proc { |severity,datetime,progname,msg| "#{progname} #{msg}\n" }
|
|
46
|
+
@logger.level = options.verbose ? Logger::DEBUG : Logger::WARN
|
|
47
|
+
|
|
48
|
+
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
49
|
+
@logger.debug(dir)
|
|
50
|
+
|
|
51
|
+
showoff_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
52
|
+
if Dir.pwd == showoff_dir
|
|
53
|
+
options.pres_dir = "#{showoff_dir}/example"
|
|
54
|
+
@root_path = "."
|
|
55
|
+
else
|
|
56
|
+
options.pres_dir ||= Dir.pwd
|
|
57
|
+
@root_path = ".."
|
|
58
|
+
end
|
|
59
|
+
options.pres_dir = File.expand_path(options.pres_dir)
|
|
60
|
+
if (options.pres_file)
|
|
61
|
+
puts "Using #{options.pres_file}"
|
|
62
|
+
ShowOffUtils.presentation_config_file = options.pres_file
|
|
63
|
+
end
|
|
64
|
+
puts "Serving presentation from #{options.pres_dir}"
|
|
65
|
+
@cached_image_size = {}
|
|
66
|
+
@logger.debug options.pres_dir
|
|
67
|
+
@pres_name = options.pres_dir.split('/').pop
|
|
68
|
+
require_ruby_files
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def require_ruby_files
|
|
72
|
+
Dir.glob("#{options.pres_dir}/*.rb").map { |path| require path }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
helpers do
|
|
76
|
+
def load_section_files(section)
|
|
77
|
+
section = File.join(options.pres_dir, section)
|
|
78
|
+
files = Dir.glob("#{section}/**/*").sort
|
|
79
|
+
@logger.debug files
|
|
80
|
+
files
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def css_files
|
|
84
|
+
Dir.glob("#{options.pres_dir}/*.css").map { |path| File.basename(path) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def js_files
|
|
88
|
+
Dir.glob("#{options.pres_dir}/*.js").map { |path| File.basename(path) }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def preshow_files
|
|
93
|
+
Dir.glob("#{options.pres_dir}/_preshow/*").map { |path| File.basename(path) }.to_json
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def process_markdown(name, content, static=false, pdf=false)
|
|
97
|
+
|
|
98
|
+
# if there are no !SLIDE markers, then make every H1 define a new slide
|
|
99
|
+
unless content =~ /^\<?!SLIDE/m
|
|
100
|
+
content = content.gsub(/^# /m, "<!SLIDE bullets>\n# ")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
slides = content.split(/^<?!SLIDE/)
|
|
104
|
+
slides.delete('')
|
|
105
|
+
final = ''
|
|
106
|
+
if slides.size > 1
|
|
107
|
+
seq = 1
|
|
108
|
+
end
|
|
109
|
+
slides.each do |slide|
|
|
110
|
+
md = ''
|
|
111
|
+
# extract content classes
|
|
112
|
+
lines = slide.split("\n")
|
|
113
|
+
content_classes = lines.shift.strip.chomp('>').split rescue []
|
|
114
|
+
slide = lines.join("\n")
|
|
115
|
+
# add content class too
|
|
116
|
+
content_classes.unshift "content"
|
|
117
|
+
# extract transition, defaulting to none
|
|
118
|
+
transition = 'none'
|
|
119
|
+
content_classes.delete_if { |x| x =~ /^transition=(.+)/ && transition = $1 }
|
|
120
|
+
# extract id, defaulting to none
|
|
121
|
+
id = nil
|
|
122
|
+
content_classes.delete_if { |x| x =~ /^#([\w-]+)/ && id = $1 }
|
|
123
|
+
@logger.debug "id: #{id}" if id
|
|
124
|
+
@logger.debug "classes: #{content_classes.inspect}"
|
|
125
|
+
@logger.debug "transition: #{transition}"
|
|
126
|
+
# create html
|
|
127
|
+
md += "<div"
|
|
128
|
+
md += " id=\"#{id}\"" if id
|
|
129
|
+
md += " class=\"slide\" data-transition=\"#{transition}\">"
|
|
130
|
+
if seq
|
|
131
|
+
md += "<div class=\"#{content_classes.join(' ')}\" ref=\"#{name}/#{seq.to_s}\">\n"
|
|
132
|
+
seq += 1
|
|
133
|
+
else
|
|
134
|
+
md += "<div class=\"#{content_classes.join(' ')}\" ref=\"#{name}\">\n"
|
|
135
|
+
end
|
|
136
|
+
sl = Markdown.new(slide).to_html
|
|
137
|
+
sl = update_image_paths(name, sl, static, pdf)
|
|
138
|
+
md += sl
|
|
139
|
+
md += "</div>\n"
|
|
140
|
+
md += "</div>\n"
|
|
141
|
+
final += update_commandline_code(md)
|
|
142
|
+
final = update_p_classes(final)
|
|
143
|
+
end
|
|
144
|
+
final
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# find any lines that start with a <p>.(something) and turn them into <p class="something">
|
|
148
|
+
def update_p_classes(markdown)
|
|
149
|
+
markdown.gsub(/<p>\.(.*?) /, '<p class="\1">')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def update_image_paths(path, slide, static=false, pdf=false)
|
|
153
|
+
paths = path.split('/')
|
|
154
|
+
paths.pop
|
|
155
|
+
path = paths.join('/')
|
|
156
|
+
replacement_prefix = static ?
|
|
157
|
+
( pdf ? %(img src="file://#{options.pres_dir}/#{path}) : %(img src="./file/#{path}) ) :
|
|
158
|
+
%(img src="/image/#{path})
|
|
159
|
+
slide.gsub(/img src=\"(.*?)\"/) do |s|
|
|
160
|
+
img_path = File.join(path, $1)
|
|
161
|
+
w, h = get_image_size(img_path)
|
|
162
|
+
src = %(#{replacement_prefix}/#{$1}")
|
|
163
|
+
if w && h
|
|
164
|
+
src << %( width="#{w}" height="#{h}")
|
|
165
|
+
end
|
|
166
|
+
src
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
if defined?(Magick)
|
|
171
|
+
def get_image_size(path)
|
|
172
|
+
if !cached_image_size.key?(path)
|
|
173
|
+
img = Magick::Image.ping(path).first
|
|
174
|
+
# don't set a size for svgs so they can expand to fit their container
|
|
175
|
+
if img.mime_type == 'image/svg+xml'
|
|
176
|
+
cached_image_size[path] = [nil, nil]
|
|
177
|
+
else
|
|
178
|
+
cached_image_size[path] = [img.columns, img.rows]
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
cached_image_size[path]
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
def get_image_size(path)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def update_commandline_code(slide)
|
|
189
|
+
html = Nokogiri::XML.parse(slide)
|
|
190
|
+
parser = CommandlineParser.new
|
|
191
|
+
|
|
192
|
+
html.css('pre').each do |pre|
|
|
193
|
+
pre.css('code').each do |code|
|
|
194
|
+
out = code.text
|
|
195
|
+
lines = out.split("\n")
|
|
196
|
+
if lines.first[0, 3] == '@@@'
|
|
197
|
+
lang = lines.shift.gsub('@@@', '').strip
|
|
198
|
+
pre.set_attribute('class', 'sh_' + lang.downcase)
|
|
199
|
+
code.content = lines.join("\n")
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
html.css('.commandline > pre > code').each do |code|
|
|
205
|
+
out = code.text
|
|
206
|
+
code.content = ''
|
|
207
|
+
tree = parser.parse(out)
|
|
208
|
+
transform = Parslet::Transform.new do
|
|
209
|
+
rule(:prompt => simple(:prompt), :input => simple(:input), :output => simple(:output)) do
|
|
210
|
+
command = Nokogiri::XML::Node.new('code', html)
|
|
211
|
+
command.set_attribute('class', 'command')
|
|
212
|
+
command.content = "#{prompt} #{input}"
|
|
213
|
+
code << command
|
|
214
|
+
|
|
215
|
+
# Add newline after the input so that users can
|
|
216
|
+
# advance faster than the typewriter effect
|
|
217
|
+
# and still keep inputs on separate lines.
|
|
218
|
+
code << "\n"
|
|
219
|
+
|
|
220
|
+
unless output.to_s.empty?
|
|
221
|
+
|
|
222
|
+
result = Nokogiri::XML::Node.new('code', html)
|
|
223
|
+
result.set_attribute('class', 'result')
|
|
224
|
+
result.content = output
|
|
225
|
+
code << result
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
transform.apply(tree)
|
|
230
|
+
end
|
|
231
|
+
html.root.to_s
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def get_slides_html(static=false, pdf=false)
|
|
235
|
+
sections = ShowOffUtils.showoff_sections(options.pres_dir,@logger)
|
|
236
|
+
files = []
|
|
237
|
+
if sections
|
|
238
|
+
sections.each do |section|
|
|
239
|
+
files << load_section_files(section)
|
|
240
|
+
end
|
|
241
|
+
files = files.flatten
|
|
242
|
+
files = files.select { |f| f =~ /.md$/ }
|
|
243
|
+
data = ''
|
|
244
|
+
files.each do |f|
|
|
245
|
+
fname = f.gsub(options.pres_dir + '/', '').gsub('.md', '')
|
|
246
|
+
data += process_markdown(fname, File.read(f), static, pdf)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
data
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def inline_css(csses, pre = nil)
|
|
253
|
+
css_content = '<style type="text/css">'
|
|
254
|
+
csses.each do |css_file|
|
|
255
|
+
if pre
|
|
256
|
+
css_file = File.join(File.dirname(__FILE__), '..', pre, css_file)
|
|
257
|
+
else
|
|
258
|
+
css_file = File.join(options.pres_dir, css_file)
|
|
259
|
+
end
|
|
260
|
+
css_content += File.read(css_file)
|
|
261
|
+
end
|
|
262
|
+
css_content += '</style>'
|
|
263
|
+
css_content
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def inline_js(jses, pre = nil)
|
|
267
|
+
js_content = '<script type="text/javascript">'
|
|
268
|
+
jses.each do |js_file|
|
|
269
|
+
if pre
|
|
270
|
+
js_file = File.join(File.dirname(__FILE__), '..', pre, js_file)
|
|
271
|
+
else
|
|
272
|
+
js_file = File.join(options.pres_dir, js_file)
|
|
273
|
+
end
|
|
274
|
+
js_content += File.read(js_file)
|
|
275
|
+
end
|
|
276
|
+
js_content += '</script>'
|
|
277
|
+
js_content
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def inline_all_js(jses_directory)
|
|
281
|
+
inline_js(Dir.entries(File.join(File.dirname(__FILE__), '..', jses_directory)).find_all{|filename| filename.length > 2 }, jses_directory)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def index(static=false)
|
|
285
|
+
if static
|
|
286
|
+
@title = ShowOffUtils.showoff_title
|
|
287
|
+
@slides = get_slides_html(static)
|
|
288
|
+
@asset_path = "./"
|
|
289
|
+
end
|
|
290
|
+
erb :index
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def clean_link(href)
|
|
294
|
+
if href && href[0, 1] == '/'
|
|
295
|
+
href = href[1, href.size]
|
|
296
|
+
end
|
|
297
|
+
href
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def assets_needed
|
|
301
|
+
assets = ["index", "slides"]
|
|
302
|
+
|
|
303
|
+
index = erb :index
|
|
304
|
+
html = Nokogiri::XML.parse(index)
|
|
305
|
+
html.css('head link').each do |link|
|
|
306
|
+
href = clean_link(link['href'])
|
|
307
|
+
assets << href if href
|
|
308
|
+
end
|
|
309
|
+
html.css('head script').each do |link|
|
|
310
|
+
href = clean_link(link['src'])
|
|
311
|
+
assets << href if href
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
slides = get_slides_html
|
|
315
|
+
html = Nokogiri::XML.parse("<slides>" + slides + "</slides>")
|
|
316
|
+
html.css('img').each do |link|
|
|
317
|
+
href = clean_link(link['src'])
|
|
318
|
+
assets << href if href
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
css = Dir.glob("#{options.public}/**/*.css").map { |path| path.gsub(options.public + '/', '') }
|
|
322
|
+
assets << css
|
|
323
|
+
|
|
324
|
+
js = Dir.glob("#{options.public}/**/*.js").map { |path| path.gsub(options.public + '/', '') }
|
|
325
|
+
assets << js
|
|
326
|
+
|
|
327
|
+
assets.uniq.join("\n")
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def slides(static=false)
|
|
331
|
+
get_slides_html(static)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def onepage(static=false)
|
|
335
|
+
@slides = get_slides_html(static)
|
|
336
|
+
erb :onepage
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def pdf(static=true)
|
|
340
|
+
@slides = get_slides_html(static, true)
|
|
341
|
+
@no_js = false
|
|
342
|
+
html = erb :onepage
|
|
343
|
+
# TODO make a random filename
|
|
344
|
+
|
|
345
|
+
# PDFKit.new takes the HTML and any options for wkhtmltopdf
|
|
346
|
+
# run `wkhtmltopdf --extended-help` for a full list of options
|
|
347
|
+
kit = PDFKit.new(html, :page_size => 'Letter', :orientation => 'Landscape')
|
|
348
|
+
|
|
349
|
+
# Save the PDF to a file
|
|
350
|
+
file = kit.to_file('/tmp/preso.pdf')
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def self.do_static(what)
|
|
357
|
+
what = "index" if !what
|
|
358
|
+
|
|
359
|
+
# Nasty hack to get the actual ShowOff module
|
|
360
|
+
showoff = ShowOff.new
|
|
361
|
+
while !showoff.is_a?(ShowOff)
|
|
362
|
+
showoff = showoff.instance_variable_get(:@app)
|
|
363
|
+
end
|
|
364
|
+
name = showoff.instance_variable_get(:@pres_name)
|
|
365
|
+
path = showoff.instance_variable_get(:@root_path)
|
|
366
|
+
data = showoff.send(what, true)
|
|
367
|
+
if data.is_a?(File)
|
|
368
|
+
FileUtils.cp(data.path, "#{name}.pdf")
|
|
369
|
+
else
|
|
370
|
+
out = "#{path}/#{name}/static"
|
|
371
|
+
# First make a directory
|
|
372
|
+
FileUtils.makedirs(out)
|
|
373
|
+
# Then write the html
|
|
374
|
+
file = File.new("#{out}/index.html", "w")
|
|
375
|
+
file.puts(data)
|
|
376
|
+
file.close
|
|
377
|
+
# Now copy all the js and css
|
|
378
|
+
my_path = File.join( File.dirname(__FILE__), '..', 'public')
|
|
379
|
+
["js", "css"].each { |dir|
|
|
380
|
+
FileUtils.copy_entry("#{my_path}/#{dir}", "#{out}/#{dir}")
|
|
381
|
+
}
|
|
382
|
+
# And copy the directory
|
|
383
|
+
Dir.glob("#{my_path}/#{name}/*").each { |subpath|
|
|
384
|
+
base = File.basename(subpath)
|
|
385
|
+
next if "static" == base
|
|
386
|
+
next unless File.directory?(subpath) || base.match(/\.(css|js)$/)
|
|
387
|
+
FileUtils.copy_entry(subpath, "#{out}/#{base}")
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
# Set up file dir
|
|
391
|
+
file_dir = File.join(out, 'file')
|
|
392
|
+
FileUtils.makedirs(file_dir)
|
|
393
|
+
pres_dir = showoff.options.pres_dir
|
|
394
|
+
|
|
395
|
+
# ..., copy all user-defined styles and javascript files
|
|
396
|
+
Dir.glob("#{pres_dir}/*.{css,js}").each { |path|
|
|
397
|
+
FileUtils.copy(path, File.join(file_dir, File.basename(path)))
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
# ... and copy all needed image files
|
|
401
|
+
data.scan(/img src=\".\/file\/(.*?)\"/).flatten.each do |path|
|
|
402
|
+
dir = File.dirname(path)
|
|
403
|
+
FileUtils.makedirs(File.join(file_dir, dir))
|
|
404
|
+
FileUtils.copy(File.join(pres_dir, path), File.join(file_dir, path))
|
|
405
|
+
end
|
|
406
|
+
# copy images from css too
|
|
407
|
+
Dir.glob("#{pres_dir}/*.css").each do |css_path|
|
|
408
|
+
File.open(css_path) do |file|
|
|
409
|
+
data = file.read
|
|
410
|
+
data.scan(/url\((.*)\)/).flatten.each do |path|
|
|
411
|
+
@logger.debug path
|
|
412
|
+
dir = File.dirname(path)
|
|
413
|
+
FileUtils.makedirs(File.join(file_dir, dir))
|
|
414
|
+
FileUtils.copy(File.join(pres_dir, path), File.join(file_dir, path))
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def eval_ruby code
|
|
422
|
+
eval(code).to_s
|
|
423
|
+
rescue => e
|
|
424
|
+
e.message
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
get '/eval_ruby' do
|
|
428
|
+
return eval_ruby(params[:code]) if ENV['SHOWOFF_EVAL_RUBY']
|
|
429
|
+
|
|
430
|
+
return "Ruby Evaluation is off. To turn it on set ENV['SHOWOFF_EVAL_RUBY']"
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
get %r{(?:image|file)/(.*)} do
|
|
434
|
+
path = params[:captures].first
|
|
435
|
+
full_path = File.join(options.pres_dir, path)
|
|
436
|
+
send_file full_path
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
get %r{/(.*)} do
|
|
440
|
+
@title = ShowOffUtils.showoff_title
|
|
441
|
+
what = params[:captures].first
|
|
442
|
+
what = 'index' if "" == what
|
|
443
|
+
if (what != "favicon.ico")
|
|
444
|
+
data = send(what)
|
|
445
|
+
if data.is_a?(File)
|
|
446
|
+
send_file data.path
|
|
447
|
+
else
|
|
448
|
+
data
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|