showoff 0.17.2 → 0.18.0
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.
- 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
 
    
        data/public/js/showoff.js
    CHANGED
    
    | 
         @@ -26,6 +26,10 @@ var loadSlidesPrefix 
     | 
|
| 
       26 
26 
     | 
    
         | 
| 
       27 
27 
     | 
    
         
             
            var mode = { track: true, follow: true };
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
            // a dummy websocket object to make standalone presentations easier.
         
     | 
| 
      
 30 
     | 
    
         
            +
            var ws = {}
         
     | 
| 
      
 31 
     | 
    
         
            +
            ws.send = function() { /* no-op */ }
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
       29 
33 
     | 
    
         
             
            // since javascript doesn't have a built-in way to get to cookies easily,
         
     | 
| 
       30 
34 
     | 
    
         
             
            // let's just add our own data structure.
         
     | 
| 
       31 
35 
     | 
    
         
             
            document.cookieHash = {}
         
     | 
| 
         @@ -51,6 +55,7 @@ function setupPreso(load_slides, prefix) { 
     | 
|
| 
       51 
55 
     | 
    
         
             
            	preso_started = true;
         
     | 
| 
       52 
56 
     | 
    
         | 
| 
       53 
57 
     | 
    
         
             
              if (! cssPropertySupported('flex') ) {
         
     | 
| 
      
 58 
     | 
    
         
            +
                // TODO: translate this this page!
         
     | 
| 
       54 
59 
     | 
    
         
             
                window.location = 'unsupported.html';
         
     | 
| 
       55 
60 
     | 
    
         
             
              }
         
     | 
| 
       56 
61 
     | 
    
         | 
| 
         @@ -68,7 +73,11 @@ function setupPreso(load_slides, prefix) { 
     | 
|
| 
       68 
73 
     | 
    
         | 
| 
       69 
74 
     | 
    
         
             
              setupSideMenu();
         
     | 
| 
       70 
75 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 76 
     | 
    
         
            +
              // Set up the language selector
         
     | 
| 
      
 77 
     | 
    
         
            +
              $('#languageSelector').change(function(e) { chooseLanguage(e.target.value); });
         
     | 
| 
      
 78 
     | 
    
         
            +
              chooseLanguage(null);
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              doDebugStuff();
         
     | 
| 
       72 
81 
     | 
    
         | 
| 
       73 
82 
     | 
    
         
             
            	// bind event handlers
         
     | 
| 
       74 
83 
     | 
    
         
             
            	toggleKeybinding('on');
         
     | 
| 
         @@ -92,6 +101,11 @@ function setupPreso(load_slides, prefix) { 
     | 
|
| 
       92 
101 
     | 
    
         
             
              // yes, this is a global
         
     | 
| 
       93 
102 
     | 
    
         
             
              annotations = new Annotate();
         
     | 
| 
       94 
103 
     | 
    
         | 
| 
      
 104 
     | 
    
         
            +
              // must be defined using [] syntax for a variable button name on IE.
         
     | 
| 
      
 105 
     | 
    
         
            +
              var closeLabel      = I18n.t('help.close');
         
     | 
| 
      
 106 
     | 
    
         
            +
              var buttons         = {};
         
     | 
| 
      
 107 
     | 
    
         
            +
              buttons[closeLabel] = function() { $(this).dialog( "close" ); };
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
       95 
109 
     | 
    
         
             
              $("#help-modal").dialog({
         
     | 
| 
       96 
110 
     | 
    
         
             
                autoOpen: false,
         
     | 
| 
       97 
111 
     | 
    
         
             
                dialogClass: "no-close",
         
     | 
| 
         @@ -100,22 +114,25 @@ function setupPreso(load_slides, prefix) { 
     | 
|
| 
       100 
114 
     | 
    
         
             
                modal: true,
         
     | 
| 
       101 
115 
     | 
    
         
             
                resizable: false,
         
     | 
| 
       102 
116 
     | 
    
         
             
                width: 640,
         
     | 
| 
       103 
     | 
    
         
            -
                buttons:  
     | 
| 
       104 
     | 
    
         
            -
                  Close: function() {
         
     | 
| 
       105 
     | 
    
         
            -
                    $( this ).dialog( "close" );
         
     | 
| 
       106 
     | 
    
         
            -
                  }
         
     | 
| 
       107 
     | 
    
         
            -
                }
         
     | 
| 
      
 117 
     | 
    
         
            +
                buttons: buttons
         
     | 
| 
       108 
118 
     | 
    
         
             
              });
         
     | 
| 
       109 
119 
     | 
    
         | 
| 
       110 
120 
     | 
    
         
             
              // wait until the presentation is loaded to hook up the previews.
         
     | 
| 
       111 
121 
     | 
    
         
             
              $("body").bind("showoff:loaded", function (event) {
         
     | 
| 
      
 122 
     | 
    
         
            +
                var target = $('#navigationHover');
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       112 
124 
     | 
    
         
             
                $('#navigation li a.navItem').hover(function() {
         
     | 
| 
       113 
125 
     | 
    
         
             
                  var position = $(this).position();
         
     | 
| 
       114 
     | 
    
         
            -
                   
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                  $('# 
     | 
| 
      
 126 
     | 
    
         
            +
                  var source   = slides.eq($(this).attr('rel'));
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  target.css({top: position.top, left: position.left + $('#navigation').width() + 5})
         
     | 
| 
      
 129 
     | 
    
         
            +
                  target.html(source.html());
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  copyBackground(source, target);
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  target.show();
         
     | 
| 
       117 
134 
     | 
    
         
             
                },function() {
         
     | 
| 
       118 
     | 
    
         
            -
                   
     | 
| 
      
 135 
     | 
    
         
            +
                  target.hide();
         
     | 
| 
       119 
136 
     | 
    
         
             
                });
         
     | 
| 
       120 
137 
     | 
    
         
             
              });
         
     | 
| 
       121 
138 
     | 
    
         | 
| 
         @@ -218,13 +235,17 @@ function initializePresentation(prefix) { 
     | 
|
| 
       218 
235 
     | 
    
         
             
              });
         
     | 
| 
       219 
236 
     | 
    
         | 
| 
       220 
237 
     | 
    
         
             
              $(".content form div.tools input.display").click(function(e) {
         
     | 
| 
      
 238 
     | 
    
         
            +
                var form   = $(this).closest('form');
         
     | 
| 
      
 239 
     | 
    
         
            +
                var formID = form.attr('id');
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                ws.send(JSON.stringify({ message: 'answerkey', formID: formID}));
         
     | 
| 
       221 
242 
     | 
    
         
             
                try {
         
     | 
| 
       222 
243 
     | 
    
         
             
                  // If we're a presenter, try to bust open the slave display
         
     | 
| 
       223 
     | 
    
         
            -
                  slaveWindow.renderForm( 
     | 
| 
      
 244 
     | 
    
         
            +
                  slaveWindow.renderForm(formID);
         
     | 
| 
       224 
245 
     | 
    
         
             
                }
         
     | 
| 
       225 
246 
     | 
    
         
             
                catch (e) {
         
     | 
| 
       226 
247 
     | 
    
         
             
                  console.log(e);
         
     | 
| 
       227 
     | 
    
         
            -
                  renderForm( 
     | 
| 
      
 248 
     | 
    
         
            +
                  renderForm(form);
         
     | 
| 
       228 
249 
     | 
    
         
             
                }
         
     | 
| 
       229 
250 
     | 
    
         
             
              });
         
     | 
| 
       230 
251 
     | 
    
         | 
| 
         @@ -238,9 +259,46 @@ function initializePresentation(prefix) { 
     | 
|
| 
       238 
259 
     | 
    
         
             
              // initialize mermaid, but don't render yet since the slide sizes are indeterminate
         
     | 
| 
       239 
260 
     | 
    
         
             
              mermaid.initialize({startOnLoad:false});
         
     | 
| 
       240 
261 
     | 
    
         | 
| 
      
 262 
     | 
    
         
            +
              // translate SVG images, inlining them first if needed.
         
     | 
| 
      
 263 
     | 
    
         
            +
              $('img').simpleStrings({strings: user_translations});
         
     | 
| 
      
 264 
     | 
    
         
            +
              $('svg').simpleStrings({strings: user_translations});
         
     | 
| 
      
 265 
     | 
    
         
            +
              $('.translate').simpleStrings({strings: user_translations});
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
       241 
267 
     | 
    
         
             
              $("#preso").trigger("showoff:loaded");
         
     | 
| 
       242 
268 
     | 
    
         
             
            }
         
     | 
| 
       243 
269 
     | 
    
         | 
| 
      
 270 
     | 
    
         
            +
            function copyBackground(source, target) {
         
     | 
| 
      
 271 
     | 
    
         
            +
              // to get this to properly copy over in Firefox, we need to iterate each property instead of using shorthand
         
     | 
| 
      
 272 
     | 
    
         
            +
              ['background-color',
         
     | 
| 
      
 273 
     | 
    
         
            +
               'background-image',
         
     | 
| 
      
 274 
     | 
    
         
            +
               'background-repeat',
         
     | 
| 
      
 275 
     | 
    
         
            +
               'background-position',
         
     | 
| 
      
 276 
     | 
    
         
            +
               'background-attachment'].forEach(function(property) {
         
     | 
| 
      
 277 
     | 
    
         
            +
                target.css(property, source.css(property));
         
     | 
| 
      
 278 
     | 
    
         
            +
              })
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
              // we have to do this separately so we can transform it
         
     | 
| 
      
 281 
     | 
    
         
            +
              var bgsize = source.css('background-size');
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
              var regex = /^(\d+)(\S{1,2})(?: (\d+)(\S{1,2}))?$/;
         
     | 
| 
      
 284 
     | 
    
         
            +
              var match = regex.exec(bgsize);
         
     | 
| 
      
 285 
     | 
    
         
            +
              if(match) {
         
     | 
| 
      
 286 
     | 
    
         
            +
                var width  = match[1];
         
     | 
| 
      
 287 
     | 
    
         
            +
                var unit_w = match[2];
         
     | 
| 
      
 288 
     | 
    
         
            +
                var height = match[3] || '';
         
     | 
| 
      
 289 
     | 
    
         
            +
                var unit_h = match[4] || '';
         
     | 
| 
      
 290 
     | 
    
         
            +
             
     | 
| 
      
 291 
     | 
    
         
            +
                if(unit_w != '%'                 ) { width  /= 2 };
         
     | 
| 
      
 292 
     | 
    
         
            +
                if(unit_h != '%' && height != '' ) { height /= 2 };
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
                target.css('background-size', width+unit_w+' '+height+unit_h);
         
     | 
| 
      
 295 
     | 
    
         
            +
              }
         
     | 
| 
      
 296 
     | 
    
         
            +
              else {
         
     | 
| 
      
 297 
     | 
    
         
            +
                // contain, cover, etc
         
     | 
| 
      
 298 
     | 
    
         
            +
                target.css('background-size', bgsize);
         
     | 
| 
      
 299 
     | 
    
         
            +
              }
         
     | 
| 
      
 300 
     | 
    
         
            +
            }
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
       244 
302 
     | 
    
         
             
            function zoom(presenter) {
         
     | 
| 
       245 
303 
     | 
    
         
             
              var preso = $("#preso");
         
     | 
| 
       246 
304 
     | 
    
         
             
              var hSlide = parseFloat(preso.height());
         
     | 
| 
         @@ -320,7 +378,7 @@ function setupSideMenu() { 
     | 
|
| 
       320 
378 
     | 
    
         
             
                  var question = $("#question").val()
         
     | 
| 
       321 
379 
     | 
    
         
             
                  var qid = askQuestion(question);
         
     | 
| 
       322 
380 
     | 
    
         | 
| 
       323 
     | 
    
         
            -
                  feedback_response(this,  
     | 
| 
      
 381 
     | 
    
         
            +
                  feedback_response(this, I18n.t('menu.sending'));
         
     | 
| 
       324 
382 
     | 
    
         
             
                  $("#question").val('');
         
     | 
| 
       325 
383 
     | 
    
         | 
| 
       326 
384 
     | 
    
         
             
                  var questionItem = $('<li/>').text(question).attr('id', qid);
         
     | 
| 
         @@ -474,9 +532,49 @@ function setupMenu() { 
     | 
|
| 
       474 
532 
     | 
    
         
             
              $("#navigation").append(nav);
         
     | 
| 
       475 
533 
     | 
    
         
             
            }
         
     | 
| 
       476 
534 
     | 
    
         | 
| 
      
 535 
     | 
    
         
            +
             
     | 
| 
      
 536 
     | 
    
         
            +
            // this function generates an object that consumes the JSON form of translations
         
     | 
| 
      
 537 
     | 
    
         
            +
            // provided by the i18n gem. It provides pretty nearly the same calling syntax
         
     | 
| 
      
 538 
     | 
    
         
            +
            // as the Ruby library's dot-form.
         
     | 
| 
      
 539 
     | 
    
         
            +
            //
         
     | 
| 
      
 540 
     | 
    
         
            +
            // var I18n = new translation(data);
         
     | 
| 
      
 541 
     | 
    
         
            +
            // console.log(I18n.t('some.key.to.translate'));
         
     | 
| 
      
 542 
     | 
    
         
            +
            function translation(data) {
         
     | 
| 
      
 543 
     | 
    
         
            +
              this.localized = data;
         
     | 
| 
      
 544 
     | 
    
         
            +
              this.translate = function(key) {
         
     | 
| 
      
 545 
     | 
    
         
            +
                var item = this.localized;
         
     | 
| 
      
 546 
     | 
    
         
            +
                try {
         
     | 
| 
      
 547 
     | 
    
         
            +
                  key.split('.').forEach(function(val) {
         
     | 
| 
      
 548 
     | 
    
         
            +
                    item = item[val];
         
     | 
| 
      
 549 
     | 
    
         
            +
                  });
         
     | 
| 
      
 550 
     | 
    
         
            +
                  if(typeof(item) != 'string') {
         
     | 
| 
      
 551 
     | 
    
         
            +
                    item = null;
         
     | 
| 
      
 552 
     | 
    
         
            +
                  }
         
     | 
| 
      
 553 
     | 
    
         
            +
                }
         
     | 
| 
      
 554 
     | 
    
         
            +
                catch(e) {
         
     | 
| 
      
 555 
     | 
    
         
            +
                  item = null;
         
     | 
| 
      
 556 
     | 
    
         
            +
                }
         
     | 
| 
      
 557 
     | 
    
         
            +
                return item || ("No translation for " + key);
         
     | 
| 
      
 558 
     | 
    
         
            +
              }
         
     | 
| 
      
 559 
     | 
    
         
            +
              this.t = function(key) { return this.translate(key); }
         
     | 
| 
      
 560 
     | 
    
         
            +
            }
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
            function chooseLanguage(locale) {
         
     | 
| 
      
 563 
     | 
    
         
            +
              // yay for half-baked data storage schemes
         
     | 
| 
      
 564 
     | 
    
         
            +
              newlocale = locale || document.cookieHash['locale'] || 'auto';
         
     | 
| 
      
 565 
     | 
    
         
            +
             
     | 
| 
      
 566 
     | 
    
         
            +
              if(locale){
         
     | 
| 
      
 567 
     | 
    
         
            +
                document.cookie = "locale="+newlocale;
         
     | 
| 
      
 568 
     | 
    
         
            +
                location.reload(false);
         
     | 
| 
      
 569 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 570 
     | 
    
         
            +
                $('#languageSelector').val(newlocale);
         
     | 
| 
      
 571 
     | 
    
         
            +
              }
         
     | 
| 
      
 572 
     | 
    
         
            +
            }
         
     | 
| 
      
 573 
     | 
    
         
            +
             
     | 
| 
       477 
574 
     | 
    
         
             
            // at some point this should get more sophisticated. Our needs are pretty minimal so far.
         
     | 
| 
       478 
575 
     | 
    
         
             
            function clearCookies() {
         
     | 
| 
       479 
576 
     | 
    
         
             
              document.cookie = "sidebar=;expires=Thu, 21 Sep 1979 00:00:01 UTC;";
         
     | 
| 
      
 577 
     | 
    
         
            +
              document.cookie = "locale=;expires=Thu, 21 Sep 1979 00:00:01 UTC;";
         
     | 
| 
       480 
578 
     | 
    
         
             
              document.cookie = "layout=;expires=Thu, 21 Sep 1979 00:00:01 UTC;";
         
     | 
| 
       481 
579 
     | 
    
         
             
              document.cookie = "notes=;expires=Thu, 21 Sep 1979 00:00:01 UTC;";
         
     | 
| 
       482 
580 
     | 
    
         
             
            }
         
     | 
| 
         @@ -688,6 +786,16 @@ function getSlideProgress() 
     | 
|
| 
       688 
786 
     | 
    
         
             
            	return (slidenum + 1) + '/' + slideTotal
         
     | 
| 
       689 
787 
     | 
    
         
             
            }
         
     | 
| 
       690 
788 
     | 
    
         | 
| 
      
 789 
     | 
    
         
            +
            function getAllSections()
         
     | 
| 
      
 790 
     | 
    
         
            +
            {
         
     | 
| 
      
 791 
     | 
    
         
            +
              memo = []
         
     | 
| 
      
 792 
     | 
    
         
            +
              $("div.notes-section").each(function() {
         
     | 
| 
      
 793 
     | 
    
         
            +
                section = $(this).attr('class').split(' ').filter(function(x) { return x != 'notes-section'; })[0];
         
     | 
| 
      
 794 
     | 
    
         
            +
                if(! memo.includes(section)) { memo.push(section) }
         
     | 
| 
      
 795 
     | 
    
         
            +
              });
         
     | 
| 
      
 796 
     | 
    
         
            +
              return memo
         
     | 
| 
      
 797 
     | 
    
         
            +
            }
         
     | 
| 
      
 798 
     | 
    
         
            +
             
     | 
| 
       691 
799 
     | 
    
         
             
            function getCurrentSections()
         
     | 
| 
       692 
800 
     | 
    
         
             
            {
         
     | 
| 
       693 
801 
     | 
    
         
             
              return currentSlide.find("div.notes-section").map(function() {
         
     | 
| 
         @@ -800,6 +908,15 @@ function enableForm(element) { 
     | 
|
| 
       800 
908 
     | 
    
         
             
              activityIncomplete = true;
         
     | 
| 
       801 
909 
     | 
    
         
             
            }
         
     | 
| 
       802 
910 
     | 
    
         | 
| 
      
 911 
     | 
    
         
            +
            function showFormAnswers(form) {
         
     | 
| 
      
 912 
     | 
    
         
            +
              // If we have any correct options, find the parent element, then tag all descendants as incorrect
         
     | 
| 
      
 913 
     | 
    
         
            +
              $('.slide.form\\='+form+' label.correct').parents('.form.element').find('label.response,option').addClass('incorrect');
         
     | 
| 
      
 914 
     | 
    
         
            +
              // Then remove the double tag from the correct answers.
         
     | 
| 
      
 915 
     | 
    
         
            +
              $('.slide.form\\='+form+' label.correct').removeClass('incorrect');
         
     | 
| 
      
 916 
     | 
    
         
            +
              // finally, style the slide so we can see the effects
         
     | 
| 
      
 917 
     | 
    
         
            +
              $('.slide.form\\='+form).addClass('answerkey')
         
     | 
| 
      
 918 
     | 
    
         
            +
            }
         
     | 
| 
      
 919 
     | 
    
         
            +
             
     | 
| 
       803 
920 
     | 
    
         
             
            function renderFormWatcher(element) {
         
     | 
| 
       804 
921 
     | 
    
         
             
              var form = element.attr('title');
         
     | 
| 
       805 
922 
     | 
    
         
             
              var action = $('.content form#'+form).attr('action');
         
     | 
| 
         @@ -957,10 +1074,6 @@ function connectControlChannel() { 
     | 
|
| 
       957 
1074 
     | 
    
         
             
                ws.onclose   = function()  { disconnected();       }
         
     | 
| 
       958 
1075 
     | 
    
         
             
                ws.onmessage = function(m) { parseMessage(m.data); };
         
     | 
| 
       959 
1076 
     | 
    
         
             
              }
         
     | 
| 
       960 
     | 
    
         
            -
              else {
         
     | 
| 
       961 
     | 
    
         
            -
                ws = {}
         
     | 
| 
       962 
     | 
    
         
            -
                ws.send = function() { /* no-op */ }
         
     | 
| 
       963 
     | 
    
         
            -
              }
         
     | 
| 
       964 
1077 
     | 
    
         
             
            }
         
     | 
| 
       965 
1078 
     | 
    
         | 
| 
       966 
1079 
     | 
    
         
             
            // This exists as an intermediary simply so the presenter view can override it
         
     | 
| 
         @@ -1019,6 +1132,10 @@ function parseMessage(data) { 
     | 
|
| 
       1019 
1132 
     | 
    
         
             
                    follow(command["current"], command["increment"]);
         
     | 
| 
       1020 
1133 
     | 
    
         
             
                    break;
         
     | 
| 
       1021 
1134 
     | 
    
         | 
| 
      
 1135 
     | 
    
         
            +
                  case 'answerkey':
         
     | 
| 
      
 1136 
     | 
    
         
            +
                    showFormAnswers(command["formID"]);
         
     | 
| 
      
 1137 
     | 
    
         
            +
                    break;
         
     | 
| 
      
 1138 
     | 
    
         
            +
             
     | 
| 
       1022 
1139 
     | 
    
         
             
                  case 'complete':
         
     | 
| 
       1023 
1140 
     | 
    
         
             
                    completeQuestion(command["questionID"]);
         
     | 
| 
       1024 
1141 
     | 
    
         
             
                    break;
         
     | 
| 
         @@ -1307,11 +1424,14 @@ function toggleFollow() 
     | 
|
| 
       1307 
1424 
     | 
    
         
             
              mode.follow = ! mode.follow;
         
     | 
| 
       1308 
1425 
     | 
    
         | 
| 
       1309 
1426 
     | 
    
         
             
              if(mode.follow) {
         
     | 
| 
       1310 
     | 
    
         
            -
                $("#followMode"). 
     | 
| 
      
 1427 
     | 
    
         
            +
                $("#followMode").addClass('fa-check-circle');
         
     | 
| 
      
 1428 
     | 
    
         
            +
                $("#followMode").removeClass('fa-ban');
         
     | 
| 
       1311 
1429 
     | 
    
         
             
                getPosition();
         
     | 
| 
       1312 
1430 
     | 
    
         
             
              } else {
         
     | 
| 
       1313 
     | 
    
         
            -
                $("#followMode"). 
     | 
| 
      
 1431 
     | 
    
         
            +
                $("#followMode").addClass('fa-ban');
         
     | 
| 
      
 1432 
     | 
    
         
            +
                $("#followMode").removeClass('fa-check-circle');
         
     | 
| 
       1314 
1433 
     | 
    
         
             
              }
         
     | 
| 
      
 1434 
     | 
    
         
            +
              showFooter();
         
     | 
| 
       1315 
1435 
     | 
    
         
             
            }
         
     | 
| 
       1316 
1436 
     | 
    
         | 
| 
       1317 
1437 
     | 
    
         
             
            function debug(data)
         
     | 
| 
         @@ -1429,11 +1549,10 @@ function toggleDebug () { 
     | 
|
| 
       1429 
1549 
     | 
    
         | 
| 
       1430 
1550 
     | 
    
         
             
            function reloadSlides (hard) {
         
     | 
| 
       1431 
1551 
     | 
    
         
             
              if(hard) {
         
     | 
| 
       1432 
     | 
    
         
            -
                var message = ' 
     | 
| 
      
 1552 
     | 
    
         
            +
                var message = I18n.t('reload');
         
     | 
| 
       1433 
1553 
     | 
    
         
             
              }
         
     | 
| 
       1434 
1554 
     | 
    
         
             
              else {
         
     | 
| 
       1435 
     | 
    
         
            -
                var message =  
     | 
| 
       1436 
     | 
    
         
            -
                message    += '(Use `RELOAD` to fully reload the entire UI)';
         
     | 
| 
      
 1555 
     | 
    
         
            +
                var message = I18n.t('refresh');
         
     | 
| 
       1437 
1556 
     | 
    
         
             
              }
         
     | 
| 
       1438 
1557 
     | 
    
         | 
| 
       1439 
1558 
     | 
    
         
             
              if (confirm(message)) {
         
     | 
| 
         @@ -1445,6 +1564,19 @@ function toggleFooter() { 
     | 
|
| 
       1445 
1564 
     | 
    
         
             
            	$('#footer').toggle()
         
     | 
| 
       1446 
1565 
     | 
    
         
             
            }
         
     | 
| 
       1447 
1566 
     | 
    
         | 
| 
      
 1567 
     | 
    
         
            +
            function showFooter(timeout) {
         
     | 
| 
      
 1568 
     | 
    
         
            +
              timeout = (typeof timeout !== 'undefined') ?  timeout : 5000;
         
     | 
| 
      
 1569 
     | 
    
         
            +
             
     | 
| 
      
 1570 
     | 
    
         
            +
              if($('#footer').is(':hidden')) {
         
     | 
| 
      
 1571 
     | 
    
         
            +
                $('#footer').show(200);
         
     | 
| 
      
 1572 
     | 
    
         
            +
             
     | 
| 
      
 1573 
     | 
    
         
            +
                window.setTimeout(function() {
         
     | 
| 
      
 1574 
     | 
    
         
            +
                  $('#footer').hide(200);
         
     | 
| 
      
 1575 
     | 
    
         
            +
                }, timeout);
         
     | 
| 
      
 1576 
     | 
    
         
            +
              }
         
     | 
| 
      
 1577 
     | 
    
         
            +
             
     | 
| 
      
 1578 
     | 
    
         
            +
            }
         
     | 
| 
      
 1579 
     | 
    
         
            +
             
     | 
| 
       1448 
1580 
     | 
    
         
             
            function toggleHelp () {
         
     | 
| 
       1449 
1581 
     | 
    
         
             
              var help = $("#help-modal");
         
     | 
| 
       1450 
1582 
     | 
    
         
             
              help.dialog("isOpen") ? help.dialog("close") : help.dialog("open");
         
     | 
| 
         @@ -1599,7 +1731,7 @@ function togglePreShow() { 
     | 
|
| 
       1599 
1731 
     | 
    
         
             
                }
         
     | 
| 
       1600 
1732 
     | 
    
         | 
| 
       1601 
1733 
     | 
    
         
             
              } else {
         
     | 
| 
       1602 
     | 
    
         
            -
                var seconds = parseFloat(prompt( 
     | 
| 
      
 1734 
     | 
    
         
            +
                var seconds = parseFloat(prompt(I18n.t('preshow.prompt')) * 60);
         
     | 
| 
       1603 
1735 
     | 
    
         | 
| 
       1604 
1736 
     | 
    
         
             
                try {
         
     | 
| 
       1605 
1737 
     | 
    
         
             
                  slaveWindow.setupPreShow(seconds);
         
     | 
| 
         @@ -1658,7 +1790,7 @@ function startPreShow() { 
     | 
|
| 
       1658 
1790 
     | 
    
         
             
            }
         
     | 
| 
       1659 
1791 
     | 
    
         | 
| 
       1660 
1792 
     | 
    
         
             
            function addPreShowTips(secondsLeft) {
         
     | 
| 
       1661 
     | 
    
         
            -
            	$('#preshow_timer').text(' 
     | 
| 
      
 1793 
     | 
    
         
            +
            	$('#preshow_timer').text(I18n.t('preshow.resume') + ' ' + secondsToTime(secondsLeft));
         
     | 
| 
       1662 
1794 
     | 
    
         
             
            	var des = preshow_des && preshow_des[tmpImg.attr("ref")];
         
     | 
| 
       1663 
1795 
     | 
    
         
             
            	if(des) {
         
     | 
| 
       1664 
1796 
     | 
    
         
             
            		$('#tips').show();
         
     | 
| 
         @@ -1749,7 +1881,7 @@ function setupStats(data) 
     | 
|
| 
       1749 
1881 
     | 
    
         
             
              if (viewers) {
         
     | 
| 
       1750 
1882 
     | 
    
         
             
                if (viewers.length == 1 && viewers[0][3] == 'current') {
         
     | 
| 
       1751 
1883 
     | 
    
         
             
                  $("#viewers").removeClass('zoomline');
         
     | 
| 
       1752 
     | 
    
         
            -
                  $("#viewers").text( 
     | 
| 
      
 1884 
     | 
    
         
            +
                  $("#viewers").text(I18n.t('stats.allcurrent'));
         
     | 
| 
       1753 
1885 
     | 
    
         
             
                }
         
     | 
| 
       1754 
1886 
     | 
    
         
             
                else {
         
     | 
| 
       1755 
1887 
     | 
    
         
             
                  $("#viewers").zoomline({
         
     | 
| 
         @@ -0,0 +1,96 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* Example usage:
         
     | 
| 
      
 2 
     | 
    
         
            +
                var translations = {
         
     | 
| 
      
 3 
     | 
    
         
            +
                  en: {
         
     | 
| 
      
 4 
     | 
    
         
            +
                    'greeting': 'Hello there!',
         
     | 
| 
      
 5 
     | 
    
         
            +
                    'farewell': "Goodbye.'
         
     | 
| 
      
 6 
     | 
    
         
            +
                  },
         
     | 
| 
      
 7 
     | 
    
         
            +
                  fr: {
         
     | 
| 
      
 8 
     | 
    
         
            +
                    'greeting': 'Bonjour!',
         
     | 
| 
      
 9 
     | 
    
         
            +
                    'farewell': "Au revoir.'}.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  es: {
         
     | 
| 
      
 11 
     | 
    
         
            +
                    'greeting': 'Hola!',
         
     | 
| 
      
 12 
     | 
    
         
            +
                    'farewell': "Adios amigo.'
         
     | 
| 
      
 13 
     | 
    
         
            +
                  }
         
     | 
| 
      
 14 
     | 
    
         
            +
                };
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              $(document).ready(function(){
         
     | 
| 
      
 17 
     | 
    
         
            +
                var lang = translations.es;
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                $('img').simpleStrings({strings: lang});
         
     | 
| 
      
 20 
     | 
    
         
            +
                $('svg').simpleStrings({strings: lang});
         
     | 
| 
      
 21 
     | 
    
         
            +
                $('.translate').simpleStrings({strings: lang}); // matches tags like <span class="translate">{{greeting}}</span>
         
     | 
| 
      
 22 
     | 
    
         
            +
              });
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            */
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            (function ( $ ) {
         
     | 
| 
      
 27 
     | 
    
         
            +
                $.fn.simpleStrings = function(options) {
         
     | 
| 
      
 28 
     | 
    
         
            +
                  var settings = $.extend({
         
     | 
| 
      
 29 
     | 
    
         
            +
                    strings: {}
         
     | 
| 
      
 30 
     | 
    
         
            +
                  }, options );
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  function translate(item) {
         
     | 
| 
      
 33 
     | 
    
         
            +
                    item = $(item);
         
     | 
| 
      
 34 
     | 
    
         
            +
                    var text = item.text();
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    if(matches = text.match(/^{{(.*)}}$/) ) {
         
     | 
| 
      
 37 
     | 
    
         
            +
                      keyword = matches[1];
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                      if(keyword in settings.strings) {
         
     | 
| 
      
 40 
     | 
    
         
            +
                        item.text(settings.strings[keyword]);
         
     | 
| 
      
 41 
     | 
    
         
            +
                      }
         
     | 
| 
      
 42 
     | 
    
         
            +
                    }
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    return item;
         
     | 
| 
      
 45 
     | 
    
         
            +
                  }
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  function inline_svg(img, callback) {
         
     | 
| 
      
 48 
     | 
    
         
            +
                    var source = img.attr('src');
         
     | 
| 
      
 49 
     | 
    
         
            +
                    var imgId  = img.attr('id');
         
     | 
| 
      
 50 
     | 
    
         
            +
                    var klass  = img.attr('class');
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    $.get(source, function( data ) {
         
     | 
| 
      
 53 
     | 
    
         
            +
                      var svg = $(data).find('svg');
         
     | 
| 
      
 54 
     | 
    
         
            +
                      svg.attr('id', imgId);
         
     | 
| 
      
 55 
     | 
    
         
            +
                      svg.attr('class', klass);
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                      if (typeof callback === 'function') {
         
     | 
| 
      
 58 
     | 
    
         
            +
                        callback.call(svg);
         
     | 
| 
      
 59 
     | 
    
         
            +
                      }
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                      img.replaceWith(svg);
         
     | 
| 
      
 62 
     | 
    
         
            +
                      console.log( "Inlined SVG image: " + source);
         
     | 
| 
      
 63 
     | 
    
         
            +
                    });
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  }
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  return this.each(function() {
         
     | 
| 
      
 68 
     | 
    
         
            +
                    var item = $(this);
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    // we can only translate img tags if they're referencing svg images
         
     | 
| 
      
 71 
     | 
    
         
            +
                    if(item.is('img')) {
         
     | 
| 
      
 72 
     | 
    
         
            +
                      // nested if because we don't want images to match the final else
         
     | 
| 
      
 73 
     | 
    
         
            +
                      if(item.attr('src').match(/.*\.svg$/i)) {
         
     | 
| 
      
 74 
     | 
    
         
            +
                        inline_svg(item, function(){
         
     | 
| 
      
 75 
     | 
    
         
            +
                          $(this).find('text, p').each(function(){
         
     | 
| 
      
 76 
     | 
    
         
            +
                            translate(this);
         
     | 
| 
      
 77 
     | 
    
         
            +
                          });
         
     | 
| 
      
 78 
     | 
    
         
            +
                        });
         
     | 
| 
      
 79 
     | 
    
         
            +
                      }
         
     | 
| 
      
 80 
     | 
    
         
            +
                    }
         
     | 
| 
      
 81 
     | 
    
         
            +
                    else if(item.is('svg')) {
         
     | 
| 
      
 82 
     | 
    
         
            +
                      // svg images already inlined. Translate by finding all texty elements
         
     | 
| 
      
 83 
     | 
    
         
            +
                      item.find('text, p').each(function(){
         
     | 
| 
      
 84 
     | 
    
         
            +
                        translate(this);
         
     | 
| 
      
 85 
     | 
    
         
            +
                      });
         
     | 
| 
      
 86 
     | 
    
         
            +
                    }
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else {
         
     | 
| 
      
 88 
     | 
    
         
            +
                      // everything else. We'll try to translate, as long as there's .text()
         
     | 
| 
      
 89 
     | 
    
         
            +
                      translate(item);
         
     | 
| 
      
 90 
     | 
    
         
            +
                    }
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    return this;
         
     | 
| 
      
 93 
     | 
    
         
            +
                  });
         
     | 
| 
      
 94 
     | 
    
         
            +
                };
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            }(jQuery));
         
     | 
    
        data/views/404.erb
    CHANGED
    
    
    
        data/views/download.erb
    CHANGED
    
    | 
         @@ -6,8 +6,8 @@ 
     | 
|
| 
       6 
6 
     | 
    
         
             
            </head>
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            <body id="download">
         
     | 
| 
       9 
     | 
    
         
            -
              <div id="wrapper">  <!-- wrapper needed for presenterPopupToggle() and $.get() --> 
     | 
| 
       10 
     | 
    
         
            -
              <h1 
     | 
| 
      
 9 
     | 
    
         
            +
              <div id="wrapper">  <!-- wrapper needed for presenterPopupToggle() and $.get() -->
         
     | 
| 
      
 10 
     | 
    
         
            +
              <h1><%= I18n.t('downloads.title') %></h1>
         
     | 
| 
       11 
11 
     | 
    
         
             
              <% if @downloads %>
         
     | 
| 
       12 
12 
     | 
    
         
             
                  <%# [ enabled, slide name, [array, of, files] ] %>
         
     | 
| 
       13 
13 
     | 
    
         
             
                  <% @downloads.sort.map do |key, value| %>
         
     | 
    
        data/views/header.erb
    CHANGED
    
    | 
         @@ -15,17 +15,18 @@ 
     | 
|
| 
       15 
15 
     | 
    
         
             
              <link rel="stylesheet" type="text/css" href="<%= @asset_path %>/css/zoomline-0.0.1.css">
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery-2.1.4.min.js"></script>
         
     | 
| 
      
 18 
     | 
    
         
            +
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery-ui-1.12.1.js"></script>
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery.cycle.all-2.8.0.js"></script>
         
     | 
| 
       20 
21 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery.batchImageLoad-1.0.0.js"></script>
         
     | 
| 
       21 
22 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery.parsequery.min-6a20f83.js"></script>
         
     | 
| 
       22 
23 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery.doubletap-4ff02c5.js"></script>
         
     | 
| 
      
 24 
     | 
    
         
            +
              <script type="text/javascript" src="<%= @asset_path %>/js/highlight.pack-9.2.0.js"></script>
         
     | 
| 
       23 
25 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/jTypeWriter-1.1.js"></script>
         
     | 
| 
       24 
26 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/bigtext-0.1.8.js"></script>
         
     | 
| 
       25 
27 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/zoomline-0.0.1.js"></script>
         
     | 
| 
       26 
     | 
    
         
            -
              <script type="text/javascript" src="<%= @asset_path %>/js/ 
     | 
| 
      
 28 
     | 
    
         
            +
              <script type="text/javascript" src="<%= @asset_path %>/js/simpleStrings-0.0.1.js"></script>
         
     | 
| 
       27 
29 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/mermaid-6.0.0-min.js"></script>
         
     | 
| 
       28 
     | 
    
         
            -
              <script type="text/javascript" src="<%= @asset_path %>/js/jquery-ui-1.12.1.js"></script>
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
31 
     | 
    
         
             
              <script type="text/javascript" src="<%= @asset_path %>/js/coffee-script-1.1.3-pre.js"></script>
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
         @@ -47,9 +48,13 @@ 
     | 
|
| 
       47 
48 
     | 
    
         | 
| 
       48 
49 
     | 
    
         
             
                editUrl     = "<%= @edit %>";
         
     | 
| 
       49 
50 
     | 
    
         
             
                interactive = <%= @interactive %>;
         
     | 
| 
      
 51 
     | 
    
         
            +
                master      = <%= master_presenter? %>;
         
     | 
| 
       50 
52 
     | 
    
         | 
| 
       51 
53 
     | 
    
         
             
                keymap               = <%= JSON.pretty_generate @keymap %>;
         
     | 
| 
       52 
54 
     | 
    
         
             
                keycode_dictionary   = <%= JSON.pretty_generate @keycode_dictionary %>;
         
     | 
| 
       53 
55 
     | 
    
         
             
                keycode_shifted_keys = <%= JSON.pretty_generate @keycode_shifted_keys %>;
         
     | 
| 
      
 56 
     | 
    
         
            +
                user_translations    = <%= JSON.pretty_generate user_translations %>;
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                I18n = new translation(<%= @language.to_json %>);
         
     | 
| 
       54 
59 
     | 
    
         | 
| 
       55 
60 
     | 
    
         
             
              </script>
         
     |