showoff 0.19.4 → 0.20.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/Rakefile +24 -12
  3. data/bin/showoff +47 -24
  4. data/lib/keymap.rb +19 -5
  5. data/lib/showoff.rb +96 -44
  6. data/lib/showoff/compiler.rb +106 -0
  7. data/lib/showoff/compiler/downloads.rb +91 -0
  8. data/lib/showoff/compiler/fixups.rb +142 -0
  9. data/lib/showoff/compiler/form.rb +236 -0
  10. data/lib/showoff/compiler/glossary.rb +164 -0
  11. data/lib/showoff/compiler/i18n.rb +24 -0
  12. data/lib/showoff/compiler/notes.rb +73 -0
  13. data/lib/showoff/compiler/table_of_contents.rb +51 -0
  14. data/lib/showoff/compiler/variables.rb +71 -0
  15. data/lib/showoff/config.rb +218 -0
  16. data/lib/showoff/locale.rb +132 -0
  17. data/lib/showoff/logger.rb +15 -0
  18. data/lib/showoff/monkeypatches.rb +28 -0
  19. data/lib/showoff/presentation.rb +181 -0
  20. data/lib/showoff/presentation/section.rb +70 -0
  21. data/lib/showoff/presentation/slide.rb +113 -0
  22. data/lib/showoff/state.rb +89 -0
  23. data/lib/showoff/version.rb +2 -2
  24. data/lib/showoff_ng.rb +99 -0
  25. data/lib/showoff_utils.rb +27 -21
  26. data/public/css/font-awesome-5.6.1/css/all.min.css +5 -0
  27. data/public/css/font-awesome-5.6.1/webfonts/fa-brands-400.eot +0 -0
  28. data/public/css/font-awesome-5.6.1/webfonts/fa-brands-400.svg +1260 -0
  29. data/public/css/font-awesome-5.6.1/webfonts/fa-brands-400.ttf +0 -0
  30. data/public/css/font-awesome-5.6.1/webfonts/fa-brands-400.woff +0 -0
  31. data/public/css/font-awesome-5.6.1/webfonts/fa-brands-400.woff2 +0 -0
  32. data/public/css/font-awesome-5.6.1/webfonts/fa-regular-400.eot +0 -0
  33. data/public/css/font-awesome-5.6.1/webfonts/fa-regular-400.svg +471 -0
  34. data/public/css/font-awesome-5.6.1/webfonts/fa-regular-400.ttf +0 -0
  35. data/public/css/font-awesome-5.6.1/webfonts/fa-regular-400.woff +0 -0
  36. data/public/css/font-awesome-5.6.1/webfonts/fa-regular-400.woff2 +0 -0
  37. data/public/css/font-awesome-5.6.1/webfonts/fa-solid-900.eot +0 -0
  38. data/public/css/font-awesome-5.6.1/webfonts/fa-solid-900.svg +2760 -0
  39. data/public/css/font-awesome-5.6.1/webfonts/fa-solid-900.ttf +0 -0
  40. data/public/css/font-awesome-5.6.1/webfonts/fa-solid-900.woff +0 -0
  41. data/public/css/font-awesome-5.6.1/webfonts/fa-solid-900.woff2 +0 -0
  42. data/public/css/presenter.css +1 -0
  43. data/public/css/showoff.css +42 -10
  44. data/public/js/highlight.pack-9.15.10.js +22614 -0
  45. data/public/js/highlightjs-line-numbers.min.js +1 -0
  46. data/public/js/presenter.js +13 -11
  47. data/public/js/showoff.js +39 -31
  48. data/views/download.erb +2 -2
  49. data/views/header.erb +27 -26
  50. data/views/header_mini.erb +8 -8
  51. data/views/index.erb +56 -56
  52. data/views/onepage.erb +10 -16
  53. data/views/presenter.erb +124 -123
  54. data/views/slide.erb +29 -0
  55. data/views/stats.erb +1 -1
  56. metadata +113 -100
  57. data/locales/id.yml +0 -2
  58. data/public/css/font-awesome-4.4.0/css/font-awesome.min.css +0 -4
  59. data/public/css/font-awesome-4.4.0/fonts/FontAwesome.otf +0 -0
  60. data/public/css/font-awesome-4.4.0/fonts/fontawesome-webfont.eot +0 -0
  61. data/public/css/font-awesome-4.4.0/fonts/fontawesome-webfont.svg +0 -640
  62. data/public/css/font-awesome-4.4.0/fonts/fontawesome-webfont.ttf +0 -0
  63. data/public/css/font-awesome-4.4.0/fonts/fontawesome-webfont.woff +0 -0
  64. data/public/css/font-awesome-4.4.0/fonts/fontawesome-webfont.woff2 +0 -0
  65. data/public/js/highlight.pack-9.2.0.js +0 -15448
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a2e85b3d4cb3a4ca82c5534fd4b927092f3f3644
4
- data.tar.gz: 7db65a31bb8715347d29cad31126b289580c6dd0
2
+ SHA256:
3
+ metadata.gz: 4f74f67db7b91942fb6a135c5f66e7624653f5946ba59d4674773b2fdb386a95
4
+ data.tar.gz: c063015a1a32fd35ea7b10ee2033f725c35345fe57f2f8d6c902a98d4116884c
5
5
  SHA512:
6
- metadata.gz: e1eb97c5ad914d5a80335e0787a6672b031aa051d0ec0761f6d7ff345dc8fbdcd92c7504b81765b587b4caeb24926a0e61f93e33a95bf82e3a9c2408d087c39d
7
- data.tar.gz: cae2c69158bb9c9fd86b9169ed6c1a802ee779ffc7171aa66f835df4025c6cba6892b447e8d1c91334b781458d43a626716343788ad9dd0a85bc2576f53200be
6
+ metadata.gz: 00dc6115962031eeb962d7fc46d7d5e7e443e9a2f033fc9b5994305364f143472cb651a5ba37802ee095318099e14a1ddf63357be37a51ba824c4dd2d10519cd
7
+ data.tar.gz: 676ddf144a82192920808f2caa8b352e630449dcbc0ee19abf147f73069e3e749d0d199225ca94b92c7ea32753328c312b9c3d274a42958019ce68d5771f41e8
data/Rakefile CHANGED
@@ -67,21 +67,33 @@ task 'doc:website' => [:doc] do
67
67
  end
68
68
  end
69
69
 
70
- desc "Run tests"
71
- task :test do
72
- require 'rake/testtask'
73
-
74
- Rake::TestTask.new do |t|
75
- t.libs << 'lib'
76
- t.pattern = 'test/**/*_test.rb'
77
- t.verbose = false
70
+ # These tests are currently unmaintained.
71
+ # @todo: port and delete
72
+ #
73
+ # desc "Run tests"
74
+ # task :test do
75
+ # require 'rake/testtask'
76
+ #
77
+ # Rake::TestTask.new do |t|
78
+ # t.libs << 'lib'
79
+ # t.pattern = 'test/**/*_test.rb'
80
+ # t.verbose = false
81
+ # end
82
+ #
83
+ # suffix = "-n #{ENV['TEST']}" if ENV['TEST']
84
+ # sh "turn test/*_test.rb #{suffix}"
85
+ # end
86
+
87
+ desc "Run RSpec unit tests"
88
+ task :spec do
89
+ ENV["LOG_SPEC_ORDER"] = "true"
90
+ if ENV['verbose'] == 'true'
91
+ sh %{rspec #{ENV['TEST'] || ENV['TESTS'] || 'spec'} -fd}
92
+ else
93
+ sh %{rspec #{ENV['TEST'] || ENV['TESTS'] || 'spec'}}
78
94
  end
79
-
80
- suffix = "-n #{ENV['TEST']}" if ENV['TEST']
81
- sh "turn test/*_test.rb #{suffix}"
82
95
  end
83
96
 
84
-
85
97
  desc 'Validate translation files'
86
98
  task 'lang:check' do
87
99
  require 'yaml'
data/bin/showoff CHANGED
@@ -1,7 +1,7 @@
1
1
  #! /usr/bin/env ruby
2
2
 
3
3
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
- require 'showoff'
4
+ #require 'showoff'
5
5
  require 'showoff/version'
6
6
  require 'rubygems'
7
7
  require 'fidget'
@@ -16,7 +16,7 @@ module Wrapper
16
16
  program_desc <<-desc
17
17
  A web based presentation engine with awesome interaction features.
18
18
 
19
- ShowOff uses Markdown files with a few custom extensions to generate slides
19
+ Showoff uses Markdown files with a few custom extensions to generate slides
20
20
  that are served locally for presentation via web browser. Your audience can
21
21
  view presentations directly as well, and interact with you in many ways.
22
22
 
@@ -28,7 +28,8 @@ module Wrapper
28
28
  The simplest use case is to run `showoff serve` from the directory containing
29
29
  the showoff.json file.
30
30
  desc
31
-
31
+ switch :dev, :desc => "Use the next-gen development version of Showoff"
32
+ switch :debug, :desc => "Show application backtraces on crash"
32
33
 
33
34
  desc 'Create new showoff presentation'
34
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.'
@@ -43,9 +44,9 @@ module Wrapper
43
44
 
44
45
  c.action do |global_options,options,args|
45
46
  dir_name = args.first || '.'
46
- ShowOffUtils.create(dir_name,!options[:n],options[:d])
47
+ ShowoffUtils.create(dir_name,!options[:n],options[:d])
47
48
  if options[:n]
48
- puts "Add slides and update #{dir_name}/#{ShowOffUtils.presentation_config_file}"
49
+ puts "Add slides and update #{dir_name}/#{ShowoffUtils.presentation_config_file}"
49
50
  end
50
51
  if args.empty?
51
52
  puts "Run 'showoff serve' to see your new slideshow"
@@ -63,7 +64,7 @@ module Wrapper
63
64
  c.flag [:f,:file]
64
65
 
65
66
  c.action do |global_options,options,args|
66
- ShowOffUtils.skeleton(options[:f])
67
+ ShowoffUtils.skeleton(options[:f])
67
68
  puts "done. run 'showoff serve' to see your slideshow"
68
69
  end
69
70
  end
@@ -79,7 +80,7 @@ module Wrapper
79
80
  c.switch [:j,:json]
80
81
 
81
82
  c.action do |global_options,options,args|
82
- ShowOffUtils.info(options[:f], options[:j])
83
+ ShowoffUtils.info(options[:f], options[:j])
83
84
  end
84
85
  end
85
86
 
@@ -91,7 +92,7 @@ module Wrapper
91
92
  c.flag [:f,:file]
92
93
 
93
94
  c.action do |global_options,options,args|
94
- ShowOffUtils.validate(options[:f])
95
+ ShowoffUtils.validate(options[:f])
95
96
  end
96
97
  end
97
98
 
@@ -100,7 +101,7 @@ module Wrapper
100
101
  command :github do |c|
101
102
  c.action do |global_options,options,args|
102
103
  puts "Generating static content"
103
- ShowOffUtils.github
104
+ ShowoffUtils.github
104
105
  puts "I've updated your 'gh-pages' branch with the static version of your presentation."
105
106
  puts "Push it to GitHub to publish it. Probably something like:"
106
107
  puts
@@ -126,16 +127,16 @@ module Wrapper
126
127
  raise "Name must start with a letter and can only contain lowercase letters, numbers, and dashes." unless args.first =~ /^[a-z][a-z1-9-]*$/
127
128
 
128
129
  unless system('git remote get-url heroku')
129
- ShowOffUtils.command("heroku create #{args[0]}", "Please ensure that the heroku gem is installed and you're logged in.")
130
+ ShowoffUtils.command("heroku create #{args[0]}", "Please ensure that the heroku gem is installed and you're logged in.")
130
131
  end
131
132
 
132
- if ShowOffUtils.heroku(args[0],options[:f],options[:p])
133
- ShowOffUtils.command('bundle install', 'Please ensure that the bundler gem is installed.')
133
+ if ShowoffUtils.heroku(args[0],options[:f],options[:p])
134
+ ShowoffUtils.command('bundle install', 'Please ensure that the bundler gem is installed.')
134
135
 
135
136
  begin
136
- ShowOffUtils.command('git add Procfile Gemfile Gemfile.lock config.ru')
137
- ShowOffUtils.command('git commit -m "Herokuized by Showoff"')
138
- ShowOffUtils.command('git push heroku master')
137
+ ShowoffUtils.command('git add Procfile Gemfile Gemfile.lock config.ru')
138
+ ShowoffUtils.command('git commit -m "Herokuized by Showoff"')
139
+ ShowoffUtils.command('git push heroku master')
139
140
  rescue => e
140
141
  puts 'Git operations failed. Please correct issues, then manually commit the following files:'
141
142
  puts ' * Procfile'
@@ -212,7 +213,7 @@ module Wrapper
212
213
 
213
214
  # This is gross. A serious revamp in config file parsing is due.
214
215
  config = JSON.parse(File.read(options[:f])) rescue {}
215
- if Gem::Version.new(config['version']) > Gem::Version.new(SHOWOFF_VERSION) then
216
+ if Gem::Version.new(config['version'].to_s) > Gem::Version.new(SHOWOFF_VERSION) then
216
217
  raise "This presentation requires Showoff version #{config['version']} or greater."
217
218
  end
218
219
 
@@ -239,7 +240,7 @@ module Wrapper
239
240
  puts "
240
241
  -------------------------
241
242
 
242
- Your ShowOff presentation is now starting up.
243
+ Your Showoff presentation is now starting up.
243
244
 
244
245
  To view it plainly, visit [ #{url} ]
245
246
 
@@ -255,8 +256,8 @@ module Wrapper
255
256
  end
256
257
 
257
258
  if options[:url]
258
- ShowOffUtils.clone(options[:git_url], options[:git_branch], options[:git_path]) do
259
- ShowOff.run!(options) do |server|
259
+ ShowoffUtils.clone(options[:git_url], options[:git_branch], options[:git_path]) do
260
+ Showoff.run!(options) do |server|
260
261
  if options[:ssl]
261
262
  server.ssl = true
262
263
  server.ssl_options = ssl_options
@@ -265,7 +266,7 @@ module Wrapper
265
266
  end
266
267
 
267
268
  else
268
- ShowOff.run!(options) do |server|
269
+ Showoff.run!(options) do |server|
269
270
  if options[:ssl]
270
271
  server.ssl = true
271
272
  server.ssl_options = ssl_options
@@ -302,7 +303,7 @@ module Wrapper
302
303
 
303
304
  c.action do |global_options,options,args|
304
305
  title = args.join(" ")
305
- ShowOffUtils.add_slide(:dir => options[:d],
306
+ ShowoffUtils.add_slide(:dir => options[:d],
306
307
  :name => options[:n],
307
308
  :title => title,
308
309
  :number => !options[:u],
@@ -323,7 +324,7 @@ module Wrapper
323
324
  c.flag [:l, :lang, :language, :locale]
324
325
 
325
326
  c.action do |global_options,options,args|
326
- ShowOff.do_static(args, options)
327
+ Showoff.do_static(args, options)
327
328
  end
328
329
  end
329
330
 
@@ -331,15 +332,37 @@ module Wrapper
331
332
  arg_name 'name'
332
333
  long_desc 'Creates a PDF version of the presentation as {name}.pdf'
333
334
  command [:pdf] do |c|
335
+ c.desc 'JSON file used to describe presentation'
336
+ c.default_value "showoff.json"
337
+ c.flag [:f, :file, :pres_file]
338
+
339
+ c.desc 'Language code to generate.'
340
+ c.flag [:l, :lang, :language, :locale]
341
+
334
342
  c.action do |global_options,options,args|
335
- ShowOff.do_static(['pdf'].concat args)
343
+ Showoff.do_static(['pdf'].concat(args), options)
336
344
  end
337
345
  end
338
346
 
339
347
  pre do |global,command,options,args|
340
348
  # Pre logic here
341
- # Return true to proceed; false to abourt and not call the
349
+ # Return true to proceed; false to abort and not call the
342
350
  # chosen command
351
+
352
+ if global[:debug]
353
+ ENV['GLI_DEBUG'] = 'true'
354
+ end
355
+
356
+ if global[:dev]
357
+ require 'showoff_ng'
358
+
359
+ if options[:file]
360
+ Showoff::Config.load(options[:file])
361
+ end
362
+ else
363
+ require 'showoff'
364
+ end
365
+
343
366
  true
344
367
  end
345
368
 
data/lib/keymap.rb CHANGED
@@ -1,14 +1,21 @@
1
1
  module Keymap
2
2
  def self.default()
3
3
  {
4
- 'space' => 'NEXT',
5
4
  'd' => 'DEBUG',
6
- 'up' => 'PREV',
7
- 'left' => 'PREV',
8
- 'pageup' => 'PREVSEC',
5
+ 'space' => 'NEXT',
9
6
  'down' => 'NEXT',
10
7
  'right' => 'NEXT',
11
- 'pagedown' => 'NEXTSEC',
8
+ 'pagedown' => 'NEXT',
9
+ 'up' => 'PREV',
10
+ 'left' => 'PREV',
11
+ 'pageup' => 'PREV',
12
+ 'SPACE' => 'NEXTSEC',
13
+ 'DOWN' => 'NEXTSEC',
14
+ 'RIGHT' => 'NEXTSEC',
15
+ 'PAGEDOWN' => 'NEXTSEC',
16
+ 'UP' => 'PREVSEC',
17
+ 'LEFT' => 'PREVSEC',
18
+ 'PAGEUP' => 'PREVSEC',
12
19
  'R' => 'RELOAD',
13
20
  'r' => 'REFRESH',
14
21
  'c' => 'CONTENTS',
@@ -169,6 +176,13 @@ module Keymap
169
176
  "`" => "~",
170
177
  "=" => "+",
171
178
  "-" => "_",
179
+ "space" => "SPACE",
180
+ "down" => "DOWN",
181
+ "right" => "RIGHT",
182
+ "pagedown" => "PAGEDOWN",
183
+ "up" => "UP",
184
+ "left" => "LEFT",
185
+ "pageup" => "PAGEUP",
172
186
  }
173
187
  end
174
188
 
data/lib/showoff.rb CHANGED
@@ -28,7 +28,7 @@ end
28
28
 
29
29
  require 'tilt'
30
30
 
31
- class ShowOff < Sinatra::Application
31
+ class Showoff < Sinatra::Application
32
32
 
33
33
  attr_reader :cached_image_size
34
34
 
@@ -92,13 +92,13 @@ class ShowOff < Sinatra::Application
92
92
 
93
93
  settings.pres_dir = File.expand_path(settings.pres_dir)
94
94
  if (settings.pres_file and settings.pres_file != 'showoff.json')
95
- ShowOffUtils.presentation_config_file = settings.pres_file
95
+ ShowoffUtils.presentation_config_file = settings.pres_file
96
96
  end
97
97
 
98
98
  # Load configuration for page size and template from the
99
99
  # configuration JSON file
100
- if File.exist?(ShowOffUtils.presentation_config_file)
101
- showoff_json = JSON.parse(File.read(ShowOffUtils.presentation_config_file))
100
+ if File.exist?(ShowoffUtils.presentation_config_file)
101
+ showoff_json = JSON.parse(File.read(ShowoffUtils.presentation_config_file))
102
102
  settings.showoff_config = showoff_json
103
103
 
104
104
  # Set options for encoding, template and page size
@@ -164,9 +164,6 @@ class ShowOff < Sinatra::Application
164
164
  @pres_name = settings.pres_dir.split('/').pop
165
165
  require_ruby_files
166
166
 
167
- # Default asset path
168
- @asset_path = "./"
169
-
170
167
  # invert the logic to maintain backwards compatibility of interactivity on by default
171
168
  @interactive = ! settings.standalone rescue false
172
169
 
@@ -208,7 +205,7 @@ class ShowOff < Sinatra::Application
208
205
  Thread.new do
209
206
  loop do
210
207
  sleep 30
211
- ShowOff.flush
208
+ Showoff.flush
212
209
  end
213
210
  end
214
211
  end
@@ -217,7 +214,7 @@ class ShowOff < Sinatra::Application
217
214
  MarkdownConfig::setup(settings.pres_dir)
218
215
 
219
216
  # Process renderer config options
220
- @engine_options = ShowOffUtils.showoff_renderer_options(settings.pres_dir)
217
+ @engine_options = ShowoffUtils.showoff_renderer_options(settings.pres_dir)
221
218
 
222
219
  end
223
220
  # save stats to disk
@@ -248,7 +245,7 @@ class ShowOff < Sinatra::Application
248
245
 
249
246
  def self.pres_dir_current
250
247
  opt = {:pres_dir => Dir.pwd}
251
- ShowOff.set opt
248
+ Showoff.set opt
252
249
  end
253
250
 
254
251
  def require_ruby_files
@@ -257,11 +254,15 @@ class ShowOff < Sinatra::Application
257
254
 
258
255
  helpers do
259
256
  def css_files
260
- Dir.glob("#{settings.pres_dir}/*.css").map { |path| File.basename(path) }
257
+ base = Dir.glob("#{settings.pres_dir}/*.css").map { |path| File.basename(path) }
258
+ extra = Array(settings.showoff_config['styles'])
259
+ base + extra
261
260
  end
262
261
 
263
262
  def js_files
264
- Dir.glob("#{settings.pres_dir}/*.js").map { |path| File.basename(path) }
263
+ base = Dir.glob("#{settings.pres_dir}/*.js").map { |path| File.basename(path) }
264
+ extra = Array(settings.showoff_config['scripts'])
265
+ base + extra
265
266
  end
266
267
 
267
268
  def preshow_files
@@ -316,10 +317,12 @@ class ShowOff < Sinatra::Application
316
317
 
317
318
  # return a hash of all language codes available and the long name description of each
318
319
  def language_names
319
- Dir.glob('locales/*').inject({}) do |memo, entry|
320
- next memo unless File.directory? entry
320
+ strings = JSON.parse(File.read('locales/strings.json')) rescue {}
321
+ locales = Dir.glob('locales/*')
322
+ .select {|f| File.directory?(f) }
323
+ .map {|f| File.basename(f) }
321
324
 
322
- locale = File.basename(entry)
325
+ (strings.keys + locales).inject({}) do |memo, locale|
323
326
  memo.update(locale => get_language_name(locale))
324
327
  end
325
328
  end
@@ -366,7 +369,7 @@ class ShowOff < Sinatra::Application
366
369
 
367
370
  # Parse the context string for options and content classes
368
371
  if context and context.match(/(\[(.*?)\])?(.*)/)
369
- options = ShowOffUtils.parse_options($2)
372
+ options = ShowoffUtils.parse_options($2)
370
373
  @tpl = options["tpl"] if options["tpl"]
371
374
  @bg = options["bg"] if options["bg"]
372
375
  @classes += $3.strip.chomp('>').split if $3
@@ -506,6 +509,7 @@ class ShowOff < Sinatra::Application
506
509
 
507
510
  # Apply the template to the slide and replace the key to generate the content of the slide
508
511
  sl = process_content_for_replacements(template.gsub(/~~~CONTENT~~~/, slide.text))
512
+ sl = process_content_for_language(sl, I18n.locale)
509
513
  sl = Tilt[:markdown].new(nil, nil, @engine_options) { sl }.render
510
514
  sl = build_forms(sl, content_classes)
511
515
  sl = update_p_classes(sl)
@@ -535,6 +539,21 @@ class ShowOff < Sinatra::Application
535
539
  final
536
540
  end
537
541
 
542
+ def process_content_for_language(content, locale)
543
+ lang = locale.to_s.split('-').first
544
+ result = content
545
+
546
+ content.scan(/^((~~~LANG:([\w-]+)~~~\n)(.+?)(\n~~~ENDLANG~~~\n))/m).each do |match|
547
+ if match[2] == lang or match[2] == locale.to_s
548
+ result.sub!(match[0], match[3])
549
+ else
550
+ result.sub!(match[0], "\n")
551
+ end
552
+ end
553
+
554
+ result
555
+ end
556
+
538
557
  # This method processes the content of the slide and replaces
539
558
  # content markers with their actual value information
540
559
  def process_content_for_replacements(content)
@@ -554,7 +573,21 @@ class ShowOff < Sinatra::Application
554
573
 
555
574
  # Now check for any kind of options
556
575
  content.scan(/(~~~CONFIG:(.*?)~~~)/).each do |match|
557
- result.gsub!(match[0], settings.showoff_config[match[1]]) if settings.showoff_config.key?(match[1])
576
+ parts = match[1].split('.') # Use dots ('.') to separate Hash keys
577
+ if parts.size > 1
578
+ value = settings.showoff_config.dig(parts[0]).to_h.dig(*parts[1..-1])
579
+ else
580
+ value = settings.showoff_config.fetch(parts[0],nil)
581
+ end
582
+
583
+ unless value.is_a?(String)
584
+ msg = "#{match[0]} refers to a non-String data type (#{value.class})"
585
+ msg = "#{match[0]}: not found in settings data" if value.nil?
586
+ @logger.warn(msg)
587
+ next
588
+ end
589
+
590
+ result.gsub!(match[0], value)
558
591
  end
559
592
 
560
593
  # Load and replace any file tags
@@ -571,8 +604,11 @@ class ShowOff < Sinatra::Application
571
604
  result.gsub!(match[0], "<pre class=\"highlight\"><code class=\"#{css}\">#{file}</code></pre>")
572
605
  end
573
606
 
574
- result.gsub!(/\[(fa-.*)\]/, '<i class="fa \1"></i>')
607
+ result.gsub!(/\[(fa\w?)-(\S*)\]/, '<i class="\1 fa-\2"></i>')
575
608
 
609
+ # For fenced code blocks, translate the space separated classes into one
610
+ # colon separated string so Commonmarker doesn't ignore the rest
611
+ result.gsub!(/^`{3} *(.+)$/) {|s| "``` #{$1.split.join(':')}"}
576
612
 
577
613
  result
578
614
  end
@@ -820,7 +856,7 @@ class ShowOff < Sinatra::Application
820
856
  tools << "<input type=\"button\" class=\"display\" value=\"#{I18n.t('forms.display')}\">"
821
857
  tools << "<input type=\"submit\" class=\"save\" value=\"#{I18n.t('forms.save')}\" disabled=\"disabled\">"
822
858
  tools << '</div>'
823
- form = "<form id='#{title}' action='/form/#{title}' method='POST'>#{content}#{tools}</form>"
859
+ form = "<form id='#{title}' action='form/#{title}' method='POST'>#{content}#{tools}</form>"
824
860
  doc = Nokogiri::HTML::DocumentFragment.parse(form)
825
861
  doc.css('p').each do |p|
826
862
  if p.text =~ /^(\w*) ?(?:->)? ?(.*)? (\*?)= ?(.*)?$/
@@ -1043,11 +1079,11 @@ class ShowOff < Sinatra::Application
1043
1079
 
1044
1080
  case
1045
1081
  when opts[:static] && opts[:pdf]
1046
- replacement_prefix = "file://#{settings.pres_dir}/"
1082
+ replacement_prefix = "file://#{settings.pres_dir}"
1047
1083
  when opts[:static]
1048
- replacement_prefix = "./file/"
1084
+ replacement_prefix = './file'
1049
1085
  else
1050
- replacement_prefix = "#{@asset_path}image/"
1086
+ replacement_prefix = 'image'
1051
1087
  end
1052
1088
 
1053
1089
  doc.css('img').each do |img|
@@ -1081,8 +1117,10 @@ class ShowOff < Sinatra::Application
1081
1117
  # catch fenced code blocks from commonmarker
1082
1118
  if (lang and lang.start_with? 'language-' )
1083
1119
  pre.set_attribute('class', 'highlight')
1120
+ # turn the colon separated name back into classes
1121
+ code.set_attribute('class', lang.gsub(':', ' '))
1084
1122
 
1085
- # or weve started a code block with a Showoff language tag
1123
+ # or we've started a code block with a Showoff language tag
1086
1124
  elsif out.strip[0, 3] == '@@@'
1087
1125
  lines = out.split("\n")
1088
1126
  lang = lines.shift.gsub('@@@', '').strip
@@ -1127,7 +1165,7 @@ class ShowOff < Sinatra::Application
1127
1165
  def get_slides_html(opts={:static=>false, :pdf=>false, :toc=>false, :supplemental=>nil, :section=>nil})
1128
1166
  sections = nil
1129
1167
  Dir.chdir(get_locale_dir('locales', @locale)) do
1130
- sections = ShowOffUtils.showoff_sections(settings.pres_dir, settings.showoff_config, @logger)
1168
+ sections = ShowoffUtils.showoff_sections(settings.pres_dir, settings.showoff_config, @logger)
1131
1169
  end
1132
1170
 
1133
1171
  if sections
@@ -1195,11 +1233,9 @@ class ShowOff < Sinatra::Application
1195
1233
 
1196
1234
  def index(static=false)
1197
1235
  if static
1198
- @title = ShowOffUtils.showoff_title(settings.pres_dir)
1236
+ @title = ShowoffUtils.showoff_title(settings.pres_dir)
1199
1237
  @slides = get_slides_html(:static=>static)
1200
- @pause_msg = ShowOffUtils.pause_msg
1201
-
1202
- @asset_path = "./"
1238
+ @pause_msg = ShowoffUtils.pause_msg
1203
1239
  end
1204
1240
 
1205
1241
  # Display favicon in the window if configured
@@ -1281,7 +1317,7 @@ class ShowOff < Sinatra::Application
1281
1317
  @logger.info "Generating locale: #{@locale}"
1282
1318
 
1283
1319
  # If we're displaying from a repository, let's update it
1284
- ShowOffUtils.update(settings.verbose) if settings.url
1320
+ ShowoffUtils.update(settings.verbose) if settings.url
1285
1321
 
1286
1322
  @@slide_titles = []
1287
1323
  content = get_slides_html(:static=>static, :merged=>merged)
@@ -1291,9 +1327,14 @@ class ShowOff < Sinatra::Application
1291
1327
  content
1292
1328
  end
1293
1329
 
1294
- def print(section=nil)
1330
+ def print(section=nil, munged=false)
1295
1331
  @slides = get_slides_html(:static=>true, :toc=>true, :print=>true, :section=>section)
1296
1332
  @favicon = settings.showoff_config['favicon']
1333
+
1334
+ unless munged
1335
+ @baseurl = '../' * section.split('/').count
1336
+ end
1337
+
1297
1338
  erb :onepage
1298
1339
  end
1299
1340
 
@@ -1423,7 +1464,7 @@ class ShowOff < Sinatra::Application
1423
1464
 
1424
1465
  # PDFKit.new takes the HTML and any options for wkhtmltopdf
1425
1466
  # run `wkhtmltopdf --extended-help` for a full list of options
1426
- kit = PDFKit.new(html, ShowOffUtils.showoff_pdf_options(settings.pres_dir))
1467
+ kit = PDFKit.new(html, ShowoffUtils.showoff_pdf_options(settings.pres_dir))
1427
1468
 
1428
1469
  # Save the PDF to a file
1429
1470
  kit.to_file(name)
@@ -1437,11 +1478,11 @@ class ShowOff < Sinatra::Application
1437
1478
  what = args[0] || "index"
1438
1479
  opt = args[1]
1439
1480
 
1440
- ShowOffUtils.presentation_config_file = opts[:f]
1481
+ ShowoffUtils.presentation_config_file = opts[:f]
1441
1482
 
1442
1483
  # Sinatra now aliases new to new!
1443
1484
  # https://github.com/sinatra/sinatra/blob/v1.3.3/lib/sinatra/base.rb#L1369
1444
- showoff = ShowOff.new!
1485
+ showoff = Showoff.new!
1445
1486
 
1446
1487
  name = showoff.instance_variable_get(:@pres_name)
1447
1488
  path = showoff.instance_variable_get(:@root_path)
@@ -1457,7 +1498,7 @@ class ShowOff < Sinatra::Application
1457
1498
  data = showoff.send(what, opt)
1458
1499
  when 'print'
1459
1500
  opt ||= 'handouts'
1460
- data = showoff.send(what, opt)
1501
+ data = showoff.send(what, opt, true)
1461
1502
  else
1462
1503
  data = showoff.send(what, true)
1463
1504
  end
@@ -1477,6 +1518,8 @@ class ShowOff < Sinatra::Application
1477
1518
  ["js", "css"].each { |dir|
1478
1519
  FileUtils.copy_entry("#{my_path}/#{dir}", "#{out}/#{dir}", false, false, true)
1479
1520
  }
1521
+
1522
+ # @todo: uh. I don't know how this ever worked. my_path is showoff and name is presentation.
1480
1523
  # And copy the directory
1481
1524
  Dir.glob("#{my_path}/#{name}/*").each { |subpath|
1482
1525
  base = File.basename(subpath)
@@ -1491,8 +1534,15 @@ class ShowOff < Sinatra::Application
1491
1534
  pres_dir = showoff.settings.pres_dir
1492
1535
 
1493
1536
  # ..., copy all user-defined styles and javascript files
1494
- Dir.glob("#{pres_dir}/*.{css,js}").each { |path|
1495
- FileUtils.copy(path, File.join(file_dir, File.basename(path)))
1537
+ showoff.css_files.each { |path|
1538
+ dest = File.join(out, path)
1539
+ FileUtils.mkdir_p(File.dirname(dest))
1540
+ FileUtils.copy(path, dest)
1541
+ }
1542
+ showoff.js_files.each { |path|
1543
+ dest = File.join(out, path)
1544
+ FileUtils.mkdir_p(File.dirname(dest))
1545
+ FileUtils.copy(path, dest)
1496
1546
  }
1497
1547
 
1498
1548
  # ... and copy all needed image files
@@ -1508,12 +1558,16 @@ class ShowOff < Sinatra::Application
1508
1558
  end
1509
1559
  end
1510
1560
  # copy images from css too
1511
- Dir.glob("#{pres_dir}/*.css").each do |css_path|
1561
+ showoff.css_files.each do |css_path|
1512
1562
  File.open(css_path) do |file|
1513
1563
  data = file.read
1514
1564
  data.scan(/url\([\"\']?(?!https?:\/\/)(.*?)[\"\']?\)/).flatten.each do |path|
1515
1565
  path.gsub!(/(\#.*)$/, '') # get rid of the anchor
1516
1566
  path.gsub!(/(\?.*)$/, '') # get rid of the query
1567
+
1568
+ # resolve relative paths in the stylesheet
1569
+ path = "#{File.dirname(css_path)}/#{path}" unless path.start_with? '/'
1570
+
1517
1571
  logger.debug path
1518
1572
  dir = File.dirname(path)
1519
1573
  FileUtils.makedirs(File.join(file_dir, dir))
@@ -1917,8 +1971,8 @@ class ShowOff < Sinatra::Application
1917
1971
  # gawd, this whole routing scheme is bollocks
1918
1972
  get %r{/([^/]*)/?([^/]*)} do
1919
1973
  @locale = locale(request.cookies['locale'])
1920
- @title = ShowOffUtils.showoff_title(settings.pres_dir)
1921
- @pause_msg = ShowOffUtils.pause_msg
1974
+ @title = ShowoffUtils.showoff_title(settings.pres_dir)
1975
+ @pause_msg = ShowoffUtils.pause_msg
1922
1976
  what = params[:captures].first
1923
1977
  opt = params[:captures][1]
1924
1978
  what = 'index' if "" == what
@@ -1929,12 +1983,12 @@ class ShowOff < Sinatra::Application
1929
1983
  locked!
1930
1984
  end
1931
1985
 
1932
- @asset_path = env['SCRIPT_NAME'] == '' ? nil : env['SCRIPT_NAME'].gsub(/^\/?/, '/').gsub(/\/?$/, '/')
1933
-
1934
1986
  begin
1935
1987
  if (what != "favicon.ico")
1936
1988
  if ['supplemental', 'print'].include? what
1937
1989
  data = send(what, opt)
1990
+ elsif File.file? what
1991
+ data = File.open(what)
1938
1992
  else
1939
1993
  data = send(what)
1940
1994
  end
@@ -1953,14 +2007,12 @@ class ShowOff < Sinatra::Application
1953
2007
  end
1954
2008
 
1955
2009
  not_found do
1956
- # Why does the asset path start from cwd??
1957
- @asset_path.slice!(/^./) rescue nil
1958
2010
  @env = request.env
1959
2011
  erb :'404'
1960
2012
  end
1961
2013
 
1962
2014
  at_exit do
1963
- ShowOff.flush
2015
+ Showoff.flush
1964
2016
  end
1965
2017
 
1966
2018
  end