showoff 0.17.2 → 0.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +37 -0
- data/bin/showoff +3 -0
- data/lib/showoff.rb +164 -43
- data/lib/showoff/version.rb +1 -1
- data/lib/showoff_utils.rb +26 -14
- data/locales/README.md +25 -0
- data/locales/de.yml +160 -0
- data/locales/en.yml +160 -0
- data/locales/es.yml +160 -0
- data/locales/fr.yml +160 -0
- data/locales/ja.yml +167 -0
- data/locales/nl.yml +160 -0
- data/locales/pt.yml +160 -0
- data/public/css/presenter.css +14 -1
- data/public/css/showoff.css +54 -4
- data/public/js/presenter.js +122 -49
- data/public/js/showoff.js +157 -25
- data/public/js/simpleStrings-0.0.1.js +96 -0
- data/views/404.erb +1 -1
- data/views/download.erb +2 -2
- data/views/header.erb +7 -2
- data/views/help.erb +16 -16
- data/views/index.erb +40 -26
- data/views/presenter.erb +86 -68
- data/views/stats.erb +7 -7
- metadata +39 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa2018ebcc69b506515c2a88f49b446347256416
|
4
|
+
data.tar.gz: 97d7de5896a47cdfc5432315513819fdc060a9c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55efb2446f06b35a6cf7d0dd28144ce9aaae1dcb95de8897bacf5fd82e896750525a555762305a7f4e47ee9ba7860607b6a1ed3619b21520a77cb4f636f14a50
|
7
|
+
data.tar.gz: 420f79aea8433eb3f147600bd774a2e4c9907c3c78c78a4bcd38cb077807d14e1de24fb8ca1b3e4018fbc7ef1243b640224b239989cd03d3011608ffb173c324
|
data/Rakefile
CHANGED
@@ -69,6 +69,43 @@ task :test do
|
|
69
69
|
sh "turn test/*_test.rb #{suffix}"
|
70
70
|
end
|
71
71
|
|
72
|
+
|
73
|
+
desc 'Validate translation files'
|
74
|
+
task 'lang:check' do
|
75
|
+
require 'yaml'
|
76
|
+
|
77
|
+
def compare_keys(left, right, name, stack=nil)
|
78
|
+
left.each do |key, val|
|
79
|
+
inner = stack.nil? ? key : "#{stack}.#{key}"
|
80
|
+
compare = right[key]
|
81
|
+
|
82
|
+
case compare
|
83
|
+
when Hash
|
84
|
+
compare_keys(val, compare, name, inner)
|
85
|
+
when String
|
86
|
+
next
|
87
|
+
when NilClass
|
88
|
+
puts "Error: '#{inner}' is missing from #{name}"
|
89
|
+
else
|
90
|
+
puts "Error: '#{inner}' in #{name} is a #{compare.class}, not a Hash"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
canonical = YAML.load_file('locales/en.yml')
|
97
|
+
languages = Dir.glob('locales/*.yml').reject {|lang| lang == 'locales/en.yml' }
|
98
|
+
|
99
|
+
languages.each do |langfile|
|
100
|
+
lang = YAML.load_file(langfile)
|
101
|
+
code = File.basename(langfile, '.yml')
|
102
|
+
key = lang.keys.first
|
103
|
+
|
104
|
+
puts "Error: #{langfile} has the wrong language code (#{key})" unless code == key
|
105
|
+
compare_keys(canonical['en'], lang[key], langfile)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
72
109
|
begin
|
73
110
|
require 'mg'
|
74
111
|
MG.new("showoff.gemspec")
|
data/bin/showoff
CHANGED
@@ -304,6 +304,9 @@ module Wrapper
|
|
304
304
|
c.default_value "showoff.json"
|
305
305
|
c.flag [:f, :file, :pres_file]
|
306
306
|
|
307
|
+
c.desc 'Language code to generate.'
|
308
|
+
c.flag [:l, :lang, :language, :locale]
|
309
|
+
|
307
310
|
c.action do |global_options,options,args|
|
308
311
|
ShowOff.do_static(args, options)
|
309
312
|
end
|
data/lib/showoff.rb
CHANGED
@@ -9,6 +9,12 @@ require 'htmlentities'
|
|
9
9
|
require 'sinatra-websocket'
|
10
10
|
require 'tempfile'
|
11
11
|
|
12
|
+
require 'i18n'
|
13
|
+
require 'i18n/backend/fallbacks'
|
14
|
+
require 'rack'
|
15
|
+
require 'rack/contrib'
|
16
|
+
require 'iso-639'
|
17
|
+
|
12
18
|
here = File.expand_path(File.dirname(__FILE__))
|
13
19
|
require "#{here}/showoff_utils"
|
14
20
|
require "#{here}/commandline_parser"
|
@@ -53,6 +59,16 @@ class ShowOff < Sinatra::Application
|
|
53
59
|
set :encoding, nil
|
54
60
|
set :url, nil
|
55
61
|
|
62
|
+
# automatically select the translation based on the user's configured browser language
|
63
|
+
use Rack::Locale
|
64
|
+
|
65
|
+
configure do
|
66
|
+
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
67
|
+
I18n.load_path += Dir[File.join(settings.root, '..', 'locales', '*.yml')]
|
68
|
+
I18n.backend.load_translations
|
69
|
+
I18n.enforce_available_locales = false
|
70
|
+
end
|
71
|
+
|
56
72
|
def initialize(app=nil)
|
57
73
|
super(app)
|
58
74
|
@logger = Logger.new(STDOUT)
|
@@ -62,10 +78,6 @@ class ShowOff < Sinatra::Application
|
|
62
78
|
@review = settings.review
|
63
79
|
@execute = settings.execute
|
64
80
|
|
65
|
-
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
66
|
-
@logger.debug(dir)
|
67
|
-
|
68
|
-
showoff_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
69
81
|
settings.pres_dir ||= Dir.pwd
|
70
82
|
@root_path = "."
|
71
83
|
|
@@ -139,7 +151,7 @@ class ShowOff < Sinatra::Application
|
|
139
151
|
@slide_count = 0
|
140
152
|
@section_major = 0
|
141
153
|
@section_minor = 0
|
142
|
-
@section_title = settings.showoff_config['name'] rescue '
|
154
|
+
@section_title = settings.showoff_config['name'] rescue I18n.t('name')
|
143
155
|
@@slide_titles = [] # a list of generated slide names, used for cross references later.
|
144
156
|
|
145
157
|
@logger.debug settings.pres_template
|
@@ -183,8 +195,9 @@ class ShowOff < Sinatra::Application
|
|
183
195
|
|
184
196
|
@@downloads = Hash.new # Track downloadable files
|
185
197
|
@@cookie = nil # presenter cookie. Identifies the presenter for control messages
|
198
|
+
@@master = nil # this holds the @client_id of the master presenter, for the cases in which multiple presenters are loaded
|
186
199
|
@@current = Hash.new # The current slide that the presenter is viewing
|
187
|
-
@@cache =
|
200
|
+
@@cache = Hash.new # Cache slide content for subsequent hits
|
188
201
|
@@activity = [] # keep track of completion for activity slides
|
189
202
|
|
190
203
|
if @interactive
|
@@ -199,8 +212,11 @@ class ShowOff < Sinatra::Application
|
|
199
212
|
|
200
213
|
# Initialize Markdown Configuration
|
201
214
|
MarkdownConfig::setup(settings.pres_dir)
|
202
|
-
end
|
203
215
|
|
216
|
+
# Process renderer config options
|
217
|
+
@engine_options = ShowOffUtils.showoff_renderer_options(settings.pres_dir)
|
218
|
+
|
219
|
+
end
|
204
220
|
# save stats to disk
|
205
221
|
def self.flush
|
206
222
|
begin
|
@@ -260,6 +276,81 @@ class ShowOff < Sinatra::Application
|
|
260
276
|
end
|
261
277
|
end
|
262
278
|
|
279
|
+
# This is just a unified lookup method that takes a full locale name
|
280
|
+
# and then resolves it to an available version of the name
|
281
|
+
def with_locale(locale)
|
282
|
+
locale = locale.to_s
|
283
|
+
until (locale.empty?) do
|
284
|
+
result = yield(locale)
|
285
|
+
return result unless result.nil?
|
286
|
+
|
287
|
+
# if not found, chop off a section and try again
|
288
|
+
locale = locale.rpartition(/[-_]/).first
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# turns a locale code into a string name
|
293
|
+
def get_language_name(locale)
|
294
|
+
with_locale(locale) do |str|
|
295
|
+
result = ISO_639.find(str)
|
296
|
+
result[3] unless result.nil?
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# This function returns the directory containing translated *content*, defaulting
|
301
|
+
# to cwd. This works similarly to I18n fallback, but we cannot reuse that as it's
|
302
|
+
# a different translation mechanism.
|
303
|
+
def get_locale_dir(prefix, locale)
|
304
|
+
return '.' if locale == 'disable'
|
305
|
+
|
306
|
+
with_locale(locale) do |str|
|
307
|
+
path = "#{prefix}/#{str}"
|
308
|
+
return path if File.directory?(path)
|
309
|
+
end || '.'
|
310
|
+
end
|
311
|
+
|
312
|
+
# return a hash of all language codes available and the long name description of each
|
313
|
+
def language_names
|
314
|
+
Dir.glob('locales/*').inject({}) do |memo, entry|
|
315
|
+
next memo unless File.directory? entry
|
316
|
+
|
317
|
+
locale = File.basename(entry)
|
318
|
+
memo.update(locale => get_language_name(locale))
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# returns the minimized canonical version of the current selected content locale
|
323
|
+
# it assumes that if the user has specified a locale, that it's already minimized
|
324
|
+
# note: if the locale doesn't exist on disk, it will just default to no translation
|
325
|
+
def locale(user_locale)
|
326
|
+
if [nil, '', 'auto'].include? user_locale
|
327
|
+
languages = I18n.available_locales
|
328
|
+
I18n.fallbacks[I18n.locale].select { |f| languages.include? f }.first
|
329
|
+
else
|
330
|
+
user_locale
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# returns a hash of all translations for the current language. This is used
|
335
|
+
# for the javascript half of the translations
|
336
|
+
def get_translations
|
337
|
+
languages = I18n.backend.send(:translations)
|
338
|
+
fallback = I18n.fallbacks[I18n.locale].select { |f| languages.keys.include? f }.first
|
339
|
+
languages[fallback]
|
340
|
+
end
|
341
|
+
|
342
|
+
# Finds the language key from strings.json and returns the strings hash. This is
|
343
|
+
# used for user translations in the presentation, e.g. SVG translations.
|
344
|
+
def user_translations
|
345
|
+
return {} unless File.file? 'locales/strings.json'
|
346
|
+
strings = JSON.parse(File.read('locales/strings.json')) rescue {}
|
347
|
+
|
348
|
+
with_locale(@locale) do |key|
|
349
|
+
return strings[key] if strings.include? key
|
350
|
+
end
|
351
|
+
{}
|
352
|
+
end
|
353
|
+
|
263
354
|
# todo: move more behavior into this class
|
264
355
|
class Slide
|
265
356
|
attr_reader :classes, :text, :tpl, :bg
|
@@ -291,9 +382,8 @@ class ShowOff < Sinatra::Application
|
|
291
382
|
if settings.encoding and content.respond_to?(:force_encoding)
|
292
383
|
content.force_encoding(settings.encoding)
|
293
384
|
end
|
294
|
-
engine_options = ShowOffUtils.showoff_renderer_options(settings.pres_dir)
|
295
385
|
@logger.debug "renderer: #{Tilt[:markdown].name}"
|
296
|
-
@logger.debug "render options: #{engine_options.inspect}"
|
386
|
+
@logger.debug "render options: #{@engine_options.inspect}"
|
297
387
|
|
298
388
|
# if there are no !SLIDE markers, then make every H1 define a new slide
|
299
389
|
unless content =~ /^\<?!SLIDE/m
|
@@ -407,7 +497,7 @@ class ShowOff < Sinatra::Application
|
|
407
497
|
|
408
498
|
# Apply the template to the slide and replace the key to generate the content of the slide
|
409
499
|
sl = process_content_for_replacements(template.gsub(/~~~CONTENT~~~/, slide.text))
|
410
|
-
sl = Tilt[:markdown].new(nil, nil, engine_options) { sl }.render
|
500
|
+
sl = Tilt[:markdown].new(nil, nil, @engine_options) { sl }.render
|
411
501
|
sl = build_forms(sl, content_classes)
|
412
502
|
sl = update_p_classes(sl)
|
413
503
|
sl = process_content_for_section_tags(sl, name, opts)
|
@@ -418,7 +508,7 @@ class ShowOff < Sinatra::Application
|
|
418
508
|
content += "</div>\n"
|
419
509
|
if content_classes.include? 'activity'
|
420
510
|
content += '<span class="activityToggle">'
|
421
|
-
content += " <label for=\"activity-#{ref}\"
|
511
|
+
content += " <label for=\"activity-#{ref}\">#{I18n.t('activity_complete')}</label>"
|
422
512
|
content += " <input type=\"checkbox\" class=\"activity\" name=\"activity-#{ref}\" id=\"activity-#{ref}\">"
|
423
513
|
content += '</span>'
|
424
514
|
end
|
@@ -497,14 +587,11 @@ class ShowOff < Sinatra::Application
|
|
497
587
|
filename = File.join(settings.pres_dir, '_notes', "#{name}.md")
|
498
588
|
@logger.debug "personal notes filename: #{filename}"
|
499
589
|
if [nil, 'notes'].include? opts[:section] and File.file? filename
|
500
|
-
# TODO: shouldn't have to reparse config all the time
|
501
|
-
engine_options = ShowOffUtils.showoff_renderer_options(settings.pres_dir)
|
502
|
-
|
503
590
|
# Make sure we've got a notes div to hang personal notes from
|
504
591
|
doc.add_child '<div class="notes-section notes"></div>' if doc.css('div.notes-section.notes').empty?
|
505
592
|
doc.css('div.notes-section.notes').each do |section|
|
506
|
-
text = Tilt[:markdown].new(nil, nil, engine_options) { File.read(filename) }.render
|
507
|
-
frag = "<div class=\"personal\"><h1
|
593
|
+
text = Tilt[:markdown].new(nil, nil, @engine_options) { File.read(filename) }.render
|
594
|
+
frag = "<div class=\"personal\"><h1>#{I18n.t('presenter.notes.personal')}</h1>#{text}</div>"
|
508
595
|
note = Nokogiri::HTML::DocumentFragment.parse(frag)
|
509
596
|
|
510
597
|
if section.children.size > 0
|
@@ -715,8 +802,8 @@ class ShowOff < Sinatra::Application
|
|
715
802
|
|
716
803
|
begin
|
717
804
|
tools = '<div class="tools">'
|
718
|
-
tools <<
|
719
|
-
tools <<
|
805
|
+
tools << "<input type=\"button\" class=\"display\" value=\"#{I18n.t('forms.display')}\">"
|
806
|
+
tools << "<input type=\"submit\" value=\"#{I18n.t('forms.save')}\" disabled=\"disabled\">"
|
720
807
|
tools << '</div>'
|
721
808
|
form = "<form id='#{title}' action='/form/#{title}' method='POST'>#{content}#{tools}</form>"
|
722
809
|
doc = Nokogiri::HTML::DocumentFragment.parse(form)
|
@@ -742,7 +829,7 @@ class ShowOff < Sinatra::Application
|
|
742
829
|
def form_element(id, code, name, required, rhs, text)
|
743
830
|
required = required ? 'required' : ''
|
744
831
|
str = "<div class='form element #{required}' id='#{id}' data-name='#{code}'>"
|
745
|
-
str << "<label for='#{id}'>#{name}</label>"
|
832
|
+
str << "<label class='question' for='#{id}'>#{name}</label>"
|
746
833
|
case rhs
|
747
834
|
when /^\[\s+(\d*)\]$$/ # value = [ 5] (textarea)
|
748
835
|
str << form_element_textarea(id, code, $1)
|
@@ -873,10 +960,10 @@ class ShowOff < Sinatra::Application
|
|
873
960
|
|
874
961
|
def form_classes(modifier)
|
875
962
|
modifier.downcase!
|
876
|
-
classes = []
|
963
|
+
classes = ['response']
|
877
964
|
classes << 'correct' if modifier.include?('=')
|
878
965
|
|
879
|
-
classes.join
|
966
|
+
classes.join(' ')
|
880
967
|
end
|
881
968
|
|
882
969
|
def form_checked?(modifier)
|
@@ -1016,8 +1103,11 @@ class ShowOff < Sinatra::Application
|
|
1016
1103
|
end
|
1017
1104
|
|
1018
1105
|
def get_slides_html(opts={:static=>false, :pdf=>false, :toc=>false, :supplemental=>nil, :section=>nil})
|
1106
|
+
sections = nil
|
1107
|
+
Dir.chdir(get_locale_dir('locales', @locale)) do
|
1108
|
+
sections = ShowOffUtils.showoff_sections(settings.pres_dir, settings.showoff_config, @logger)
|
1109
|
+
end
|
1019
1110
|
|
1020
|
-
sections = ShowOffUtils.showoff_sections(settings.pres_dir, @logger)
|
1021
1111
|
if sections
|
1022
1112
|
data = ''
|
1023
1113
|
sections.each do |section, slides|
|
@@ -1102,17 +1192,11 @@ class ShowOff < Sinatra::Application
|
|
1102
1192
|
# Provide a button in the sidebar for interactive editing if configured
|
1103
1193
|
@edit = settings.showoff_config['edit'] if @review
|
1104
1194
|
|
1195
|
+
# translated UI strings, according to the current locale
|
1196
|
+
@language = get_translations()
|
1197
|
+
|
1105
1198
|
# store a cookie to tell clients apart. More reliable than using IP due to proxies, etc.
|
1106
|
-
|
1107
|
-
@client_id = guid()
|
1108
|
-
else
|
1109
|
-
if request.cookies['client_id']
|
1110
|
-
@client_id = request.cookies['client_id']
|
1111
|
-
else
|
1112
|
-
@client_id = guid()
|
1113
|
-
response.set_cookie('client_id', @client_id)
|
1114
|
-
end
|
1115
|
-
end
|
1199
|
+
manage_client_cookies()
|
1116
1200
|
|
1117
1201
|
erb :index
|
1118
1202
|
end
|
@@ -1122,8 +1206,10 @@ class ShowOff < Sinatra::Application
|
|
1122
1206
|
@issues = settings.showoff_config['issues']
|
1123
1207
|
@edit = settings.showoff_config['edit'] if @review
|
1124
1208
|
@feedback = settings.showoff_config['feedback']
|
1125
|
-
|
1126
|
-
|
1209
|
+
@language = get_translations()
|
1210
|
+
|
1211
|
+
manage_client_cookies(true)
|
1212
|
+
|
1127
1213
|
erb :presenter
|
1128
1214
|
end
|
1129
1215
|
|
@@ -1165,21 +1251,26 @@ class ShowOff < Sinatra::Application
|
|
1165
1251
|
end
|
1166
1252
|
|
1167
1253
|
def slides(static=false)
|
1254
|
+
@logger.warn "Cached presentations: #{@@cache.keys}"
|
1255
|
+
|
1256
|
+
# if we have a cache and we're not asking to invalidate it
|
1257
|
+
return @@cache[@locale] if (@@cache[@locale] and params['cache'] != 'clear')
|
1258
|
+
|
1259
|
+
@logger.warn "Generating locale: #{@locale}"
|
1260
|
+
|
1168
1261
|
# If we're displaying from a repository, let's update it
|
1169
1262
|
ShowOffUtils.update(settings.verbose) if settings.url
|
1170
1263
|
|
1171
|
-
# if we have a cache and we're not asking to invalidate it
|
1172
|
-
return @@cache if (@@cache and params['cache'] != 'clear')
|
1173
1264
|
@@slide_titles = []
|
1174
1265
|
content = get_slides_html(:static=>static)
|
1175
1266
|
|
1176
1267
|
# allow command line cache disabling
|
1177
|
-
@@cache = content unless settings.nocache
|
1268
|
+
@@cache[@locale] = content unless settings.nocache
|
1178
1269
|
content
|
1179
1270
|
end
|
1180
1271
|
|
1181
|
-
def print(
|
1182
|
-
@slides = get_slides_html(:static=>
|
1272
|
+
def print(section=nil)
|
1273
|
+
@slides = get_slides_html(:static=>true, :toc=>true, :print=>true, :section=>section)
|
1183
1274
|
@favicon = settings.showoff_config['favicon']
|
1184
1275
|
erb :onepage
|
1185
1276
|
end
|
@@ -1334,6 +1425,8 @@ class ShowOff < Sinatra::Application
|
|
1334
1425
|
path = showoff.instance_variable_get(:@root_path)
|
1335
1426
|
logger = showoff.instance_variable_get(:@logger)
|
1336
1427
|
|
1428
|
+
I18n.locale = opts[:language]
|
1429
|
+
|
1337
1430
|
case what
|
1338
1431
|
when 'supplemental'
|
1339
1432
|
data = showoff.send(what, opt, true)
|
@@ -1342,7 +1435,7 @@ class ShowOff < Sinatra::Application
|
|
1342
1435
|
data = showoff.send(what, opt)
|
1343
1436
|
when 'print'
|
1344
1437
|
opt ||= 'handouts'
|
1345
|
-
data = showoff.send(what,
|
1438
|
+
data = showoff.send(what, opt)
|
1346
1439
|
else
|
1347
1440
|
data = showoff.send(what, true)
|
1348
1441
|
end
|
@@ -1512,6 +1605,33 @@ class ShowOff < Sinatra::Application
|
|
1512
1605
|
(request.cookies['presenter'] == @@cookie)
|
1513
1606
|
end
|
1514
1607
|
|
1608
|
+
def master_presenter?
|
1609
|
+
@@master == @client_id
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
def manage_client_cookies(presenter=false)
|
1613
|
+
# store a cookie to tell clients apart. More reliable than using IP due to proxies, etc.
|
1614
|
+
if request.nil? # when running showoff static
|
1615
|
+
@client_id = guid()
|
1616
|
+
else
|
1617
|
+
if request.cookies['client_id']
|
1618
|
+
@client_id = request.cookies['client_id']
|
1619
|
+
else
|
1620
|
+
@client_id = guid()
|
1621
|
+
response.set_cookie('client_id', @client_id)
|
1622
|
+
end
|
1623
|
+
|
1624
|
+
# if we have no content translations then remove the cookie
|
1625
|
+
response.delete_cookie('locale') if language_names.empty?
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
if presenter
|
1629
|
+
@@master ||= @client_id
|
1630
|
+
@@cookie ||= guid()
|
1631
|
+
response.set_cookie('presenter', @@cookie)
|
1632
|
+
end
|
1633
|
+
end
|
1634
|
+
|
1515
1635
|
post '/form/:id' do |id|
|
1516
1636
|
client_id = request.cookies['client_id']
|
1517
1637
|
@logger.warn("Saving form answers from ip:#{request.ip} with ID of #{client_id} for id:##{id}")
|
@@ -1723,7 +1843,7 @@ class ShowOff < Sinatra::Application
|
|
1723
1843
|
control['id'] = guid()
|
1724
1844
|
EM.next_tick { settings.presenters.each{|s| s.send(control.to_json) } }
|
1725
1845
|
|
1726
|
-
when 'complete'
|
1846
|
+
when 'complete', 'answerkey'
|
1727
1847
|
EM.next_tick { settings.sockets.each{|s| s.send(control.to_json) } }
|
1728
1848
|
|
1729
1849
|
when 'annotation', 'annotationConfig'
|
@@ -1771,7 +1891,8 @@ class ShowOff < Sinatra::Application
|
|
1771
1891
|
|
1772
1892
|
# gawd, this whole routing scheme is bollocks
|
1773
1893
|
get %r{/([^/]*)/?([^/]*)} do
|
1774
|
-
@
|
1894
|
+
@locale = locale(request.cookies['locale'])
|
1895
|
+
@title = ShowOffUtils.showoff_title(settings.pres_dir)
|
1775
1896
|
@pause_msg = ShowOffUtils.pause_msg
|
1776
1897
|
what = params[:captures].first
|
1777
1898
|
opt = params[:captures][1]
|
@@ -1787,7 +1908,7 @@ class ShowOff < Sinatra::Application
|
|
1787
1908
|
|
1788
1909
|
begin
|
1789
1910
|
if (what != "favicon.ico")
|
1790
|
-
if
|
1911
|
+
if ['supplemental', 'print'].include? what
|
1791
1912
|
data = send(what, opt)
|
1792
1913
|
else
|
1793
1914
|
data = send(what)
|