showoff 0.17.1 → 0.17.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b65ae2cdb55992dc61f317faf924fd93cdefd594
4
- data.tar.gz: f4331abee28540e37e8362c52ffe87c705405f07
3
+ metadata.gz: e79f2890ed22c967bf20c13e7086bdd7e6fa441c
4
+ data.tar.gz: 5c328c3d8979191809a404b984202d2fca92a8cd
5
5
  SHA512:
6
- metadata.gz: f74cea3ee9a73a8b9240bcd7d11d909766ce6ecb38ec8fc57cea3ff1a57f803b5475b2afa0121685230154ae51c64751cb3d80972eddd71fd2d901ba58640efc
7
- data.tar.gz: 938c693644cd33d34b9945131cc6c607d32fa6f162f03f4ce4a166e9eb37532fcf0d6074b9da0e254124ed5ee1a9351d3697312fd667118077eab74a652ad0be
6
+ metadata.gz: 281b88028b291de836db367604aaadead708eb79a34f060e1231defc51b188f5dc0cf01f1ceb8ca17e1662528d6f0d168929410f75a880a7c1ca5b24f95c0071
7
+ data.tar.gz: 2408b4d8909d3f84df131a7af5069cbc5029d8f768b67d6508d83899ccafec0d549e863554ef4dbfafe921be89395e2013fe505ee1bd77eb900bba1888d66cbe
data/README.md CHANGED
@@ -64,9 +64,10 @@ you'll need to install both Ruby and the Ruby DevKit for compiling native extens
64
64
 
65
65
  ## Documentation
66
66
 
67
- Please see the [documentation](./documentation) section for further information.
67
+ Please see the user manual on the [Showoff homepage](http://puppetlabs.github.io/showoff)
68
+ for further information.
68
69
 
69
- You can generate a nice & pretty local copy of the documentation by running
70
+ You can also generate a nice & pretty local copy of the user manual by running
70
71
  `rake doc` in your clone of the repository. The generated HTML will be saved in
71
72
  the `docs` directory.
72
73
 
data/lib/showoff.rb CHANGED
@@ -185,6 +185,7 @@ class ShowOff < Sinatra::Application
185
185
  @@cookie = nil # presenter cookie. Identifies the presenter for control messages
186
186
  @@current = Hash.new # The current slide that the presenter is viewing
187
187
  @@cache = nil # Cache slide content for subsequent hits
188
+ @@activity = [] # keep track of completion for activity slides
188
189
 
189
190
  if @interactive
190
191
  # flush stats to disk periodically
@@ -415,6 +416,12 @@ class ShowOff < Sinatra::Application
415
416
 
416
417
  content += sl
417
418
  content += "</div>\n"
419
+ if content_classes.include? 'activity'
420
+ content += '<span class="activityToggle">'
421
+ content += " <label for=\"activity-#{ref}\">Activity complete</label>"
422
+ content += " <input type=\"checkbox\" class=\"activity\" name=\"activity-#{ref}\" id=\"activity-#{ref}\">"
423
+ content += '</span>'
424
+ end
418
425
  content += "<canvas class=\"annotations\"></canvas>\n"
419
426
  content += "</div>\n"
420
427
 
@@ -465,6 +472,9 @@ class ShowOff < Sinatra::Application
465
472
  result.gsub!(match[0], "<pre class=\"highlight\"><code class=\"#{css}\">#{file}</code></pre>")
466
473
  end
467
474
 
475
+ result.gsub!(/\[(fa-.*)\]/, '<i class="fa \1"></i>')
476
+
477
+
468
478
  result
469
479
  end
470
480
 
@@ -1111,6 +1121,7 @@ class ShowOff < Sinatra::Application
1111
1121
  @favicon = settings.showoff_config['favicon']
1112
1122
  @issues = settings.showoff_config['issues']
1113
1123
  @edit = settings.showoff_config['edit'] if @review
1124
+ @feedback = settings.showoff_config['feedback']
1114
1125
  @@cookie ||= guid()
1115
1126
  response.set_cookie('presenter', @@cookie)
1116
1127
  erb :presenter
@@ -1429,10 +1440,10 @@ class ShowOff < Sinatra::Application
1429
1440
  classes = code.attr('class').split rescue []
1430
1441
  lang = classes.shift =~ /language-(\S*)/ ? $1 : nil
1431
1442
 
1432
- [lang, code.text, classes]
1443
+ [lang, code.text.gsub(/^\* /, ' '), classes]
1433
1444
  end
1434
1445
  else
1435
- doc.css(classes)[index.to_i].text rescue 'Invalid code block index'
1446
+ doc.css(classes)[index.to_i].text.gsub(/^\* /, ' ') rescue 'Invalid code block index'
1436
1447
  end
1437
1448
  end
1438
1449
 
@@ -1577,6 +1588,10 @@ class ShowOff < Sinatra::Application
1577
1588
  # Docs suggest that old versions of Sinatra might provide an array here, so just make sure.
1578
1589
  filename = path.class == Array ? path.first : path
1579
1590
  @logger.debug "Editing #{filename}"
1591
+
1592
+ # When a relative path is used, it's sometimes fully expanded. But then when
1593
+ # it's passed via URL, the initial slash is lost. Here we try to get it back.
1594
+ filename = "/#{filename}" unless File.exist? filename
1580
1595
  return unless File.exist? filename
1581
1596
 
1582
1597
  if request.host != 'localhost'
@@ -1682,9 +1697,26 @@ class ShowOff < Sinatra::Application
1682
1697
  @logger.debug "Recorded current slide #{slide} for #{remote}"
1683
1698
  end
1684
1699
 
1685
-
1686
1700
  when 'position'
1687
- ws.send( { 'current' => @@current[:number] }.to_json ) unless @@cookie.nil?
1701
+ ws.send( { 'message' => 'current', 'current' => @@current[:number] }.to_json ) unless @@cookie.nil?
1702
+
1703
+ when 'activity'
1704
+ next if valid_presenter_cookie?
1705
+ remote = request.cookies['client_id']
1706
+ slide = control['slide']
1707
+ status = control['status']
1708
+ @@activity[slide] ||= {}
1709
+ @@activity[slide][remote] = status
1710
+
1711
+ current = @@current[:number]
1712
+ activity = @@activity[current] rescue nil
1713
+
1714
+ @logger.debug "Current activity status: #{activity.inspect}"
1715
+ if activity
1716
+ # select all activity on this slide where completion status is false
1717
+ count = activity.select {|viewer, status| status == false }.size
1718
+ EM.next_tick { settings.presenters.each{|s| s.send({ 'message' => 'activity', 'count' => count }.to_json) } }
1719
+ end
1688
1720
 
1689
1721
  when 'pace', 'question', 'cancel'
1690
1722
  # just forward to the presenter(s) along with a debounce in case a presenter is registered twice
@@ -1,3 +1,3 @@
1
1
  # No namespace here since ShowOff is a class and I'd have to inherit from
2
2
  # Sinatra::Application (which we don't want to load here)
3
- SHOWOFF_VERSION = '0.17.1'
3
+ SHOWOFF_VERSION = '0.17.2'
data/lib/showoff_utils.rb CHANGED
@@ -470,14 +470,15 @@ class ShowOffUtils
470
470
  end.flatten.compact.each do |filename|
471
471
  # We do this in two passes simply because most of it was already done
472
472
  # and I don't want to waste time on legacy functionality.
473
- path = File.dirname(filename)
474
- sections[path] ||= []
475
-
476
473
  if File.directory? filename
474
+ path = filename
475
+ sections[path] ||= []
477
476
  Dir.glob("#{filename}/**/*.md").sort.each do |slidefile|
478
- sections[path] << slidefile
477
+ sections[path] << slidefile
479
478
  end
480
479
  else
480
+ path = File.dirname(filename)
481
+ sections[path] ||= []
481
482
  sections[path] << filename
482
483
  end
483
484
  end
@@ -83,7 +83,7 @@
83
83
  border: none;
84
84
  border-radius: 0;
85
85
  line-height: 3em;
86
- margin-top: -1px; /* hell if I know why, but probably somewhere in jquery-ui */
86
+ vertical-align: inherit; /* overrides a jquery-ui style */
87
87
  }
88
88
 
89
89
  #links a.enabled,
@@ -208,30 +208,62 @@
208
208
  height: 40px;
209
209
  min-height: 40px;
210
210
  position: relative;
211
- background: transparent url(pace.png) no-repeat center bottom;
212
- }
213
- #paceFast,
214
- #paceSlow {
215
- display: none;
216
- }
217
- #paceFast {
218
- float: left;
219
- margin-left: 1em;
220
- }
221
- #paceSlow {
222
- float: right;
223
- margin-right: 1em;
211
+ border-bottom: 1px solid #ccc;
224
212
  }
225
- #paceMarker {
226
- left: 50%;
227
- position: absolute;
228
- transform: translate(-50%, -50%);
229
- -webkit-transform: translate(-50%, 0);
230
- -moz-transform: translate(-50%, 0);
231
- -ms-transform: translate(-50%, 0);
232
- -o-transform: translate(-50%, 0);
213
+ #feedbackPace .gradient {
214
+ position: absolute;
215
+ bottom: 0;
216
+ width: 100%;
217
+ height: 20px;
218
+ background-color:#ff0000;
219
+ filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1,startColorstr=#ff0000, endColorstr=#eeff00);
220
+ background-image:-moz-linear-gradient(left, #ff0000 10%, #eeff00 30%,#00ff00 50%,#eeff00 70%,#ff0000 90%);
221
+ background-image:linear-gradient(left, #ff0000 10%, #eeff00 30%,#00ff00 50%,#eeff00 70%,#ff0000 90%);
222
+ background-image:-webkit-linear-gradient(left, #ff0000 10%, #eeff00 30%,#00ff00 50%,#eeff00 70%,#ff0000 90%);
223
+ background-image:-o-linear-gradient(left, #ff0000 10%, #eeff00 30%,#00ff00 50%,#eeff00 70%,#ff0000 90%);
224
+ background-image:-ms-linear-gradient(left, #ff0000 10%, #eeff00 30%,#00ff00 50%,#eeff00 70%,#ff0000 90%);
225
+ background-image:-webkit-gradient(linear, left bottom, right bottom, color-stop(10%,#ff0000), color-stop(30%,#eeff00),color-stop(50%,#00ff00),color-stop(70%,#eeff00),color-stop(90%,#ff0000));
226
+ }
227
+ #feedbackPace .obscure {
228
+ position: absolute;
229
+ background-color: #f0f0f0;
230
+ bottom: 0;
231
+ height: 20px;
232
+ transition: width 0.25s;
233
+ }
234
+ #feedbackPace .obscure.left {
235
+ left: 0;
236
+ width: 50%;
237
+ border-right: 1px solid black;
238
+ }
239
+ #feedbackPace .obscure.right {
240
+ right: 0;
241
+ width: 50%;
242
+ border-left: 1px solid black;
243
+ }
233
244
 
234
- }
245
+ #paceFast,
246
+ #paceSlow {
247
+ display: none;
248
+ }
249
+ #paceFast {
250
+ float: left;
251
+ margin-left: 1em;
252
+ }
253
+ #paceSlow {
254
+ float: right;
255
+ margin-right: 1em;
256
+ }
257
+ #paceMarker {
258
+ left: 50%;
259
+ position: absolute;
260
+ transform: translate(-50%, -50%);
261
+ -webkit-transform: translate(-50%, 0);
262
+ -moz-transform: translate(-50%, 0);
263
+ -ms-transform: translate(-50%, 0);
264
+ -o-transform: translate(-50%, 0);
265
+ transition: left 0.25s;
266
+ }
235
267
 
236
268
  .submenu {
237
269
  flex-grow: 10;
@@ -574,6 +606,7 @@
574
606
  width: 90%;
575
607
  }
576
608
 
609
+ .slide.activity .count,
577
610
  #notes .count {
578
611
  display: inline-block;
579
612
  background-color: #2e2e2e;
@@ -604,6 +637,13 @@
604
637
  display: none;
605
638
  }
606
639
 
640
+ .slide.activity .count {
641
+ position: absolute;
642
+ bottom: .25em;
643
+ right: .5em;
644
+ padding: 0 0.25em;
645
+ }
646
+
607
647
 
608
648
  a.controls {
609
649
  text-decoration: none;
@@ -382,6 +382,10 @@ img#disconnected {
382
382
  margin-right: 8px;
383
383
  }
384
384
 
385
+ .sideMenu hr {
386
+ clear: both;
387
+ }
388
+
385
389
  .buttonWrapper {
386
390
  line-height: 48px;
387
391
  padding: 0 16px;
@@ -577,6 +581,12 @@ pre.highlight code.language-powershellconsole.nochrome {
577
581
  border-radius: 4px;
578
582
  }
579
583
 
584
+ pre.highlight code .highlightedLine {
585
+ background-color: #f5e2e2;
586
+ display: inline-block;
587
+ width: 100%;
588
+ }
589
+
580
590
  /* to avoid breaking changes */
581
591
  .highlight .language-shell {
582
592
  display: block;
@@ -747,14 +757,6 @@ form .element {
747
757
  /*****************
748
758
  *** modals ***
749
759
  *****************/
750
- #help-modal {
751
- font-size: .9em;
752
- }
753
-
754
- #help-modal .ui-dialog .ui-dialog-title {
755
- font-size: 1em;
756
- }
757
-
758
760
  .ui-dialog.ui-widget-content {
759
761
  border: none;
760
762
  box-shadow:0 0 25px rgba(0,0,0,0.35);
@@ -812,6 +814,15 @@ form .element {
812
814
  display: none;
813
815
  }
814
816
 
817
+ #help-modal {
818
+ display: none;
819
+ font-size: .9em;
820
+ }
821
+
822
+ #help-modal .ui-dialog .ui-dialog-title {
823
+ font-size: 1em;
824
+ }
825
+
815
826
  #help div {
816
827
  padding: 6px 0;
817
828
  }
@@ -1041,6 +1052,7 @@ form .element {
1041
1052
 
1042
1053
  .callout {
1043
1054
  padding: 1em;
1055
+ position: relative;
1044
1056
  line-height: 1.2em;
1045
1057
  border: 1px solid #222;
1046
1058
  border-radius: 4px;
@@ -1054,7 +1066,18 @@ form .element {
1054
1066
  font-size: 2em;
1055
1067
  text-decoration: inherit;
1056
1068
  position: absolute;
1057
- left: 1em;
1069
+ left: 0.3em;
1070
+ }
1071
+ .callout:after {
1072
+ font-family: FontAwesome;
1073
+ font-style: normal;
1074
+ font-weight: normal;
1075
+ font-size: 1.5em;
1076
+ text-decoration: inherit;
1077
+ position: absolute;
1078
+ left: 0.5em;
1079
+ top: 0.65em;
1080
+ color: #fff;
1058
1081
  }
1059
1082
 
1060
1083
  .callout.info,
@@ -1064,7 +1087,8 @@ form .element {
1064
1087
  .callout.stop,
1065
1088
  .callout.thumbsup,
1066
1089
  .callout.conversation,
1067
- .callout.glossary {
1090
+ .callout.glossary,
1091
+ .callout.terminal {
1068
1092
  padding-left: 3em;
1069
1093
  }
1070
1094
 
@@ -1077,6 +1101,10 @@ form .element {
1077
1101
  .callout.conversation:before { content: "\f0e5"; } /* fa-comment */
1078
1102
  .callout.glossary:before { content: "\f02d"; } /* fa-book */
1079
1103
 
1104
+ .callout.terminal:before { content: "\f0c8"; } /* fa-square */
1105
+ .callout.terminal:after { content: "\f120"; } /* fa-terminal */
1106
+
1107
+
1080
1108
  /* callouts used on error pages */
1081
1109
  .error .callout {
1082
1110
  padding-left: 4em;
@@ -1117,6 +1145,14 @@ a.term:after {
1117
1145
  *** glossary ***
1118
1146
  **********************/
1119
1147
 
1148
+ /**************************
1149
+ *** activity indicators ***
1150
+ ***************************/
1151
+ .slide.activity .activityToggle {
1152
+ position: absolute;
1153
+ bottom: 1em;
1154
+ right: 1em;
1155
+ }
1120
1156
 
1121
1157
  /* Render hidden headlines so that when we print with wkhtmltopdf, we can use section
1122
1158
  titles for page headers. it would make sense to put this in the print section, but
@@ -30,7 +30,10 @@ $(document).ready(function(){
30
30
  $("#settings").click( function() { $("#settings-modal").dialog("open"); });
31
31
  $("#slideSource a").click( function() { openEditor() });
32
32
  $("#notesToggle").click( function() { toggleNotes() });
33
- $("#clearCookies").click( function() { clearCookies() });
33
+ $("#clearCookies").click( function() {
34
+ clearCookies();
35
+ location.reload(false);
36
+ });
34
37
  $("#nextWinCancel").click( function() { chooseLayout('default') });
35
38
  $("#openNextWindow").click(function() { openNext() });
36
39
 
@@ -514,6 +517,15 @@ function updatePace() {
514
517
  var position = Math.max(Math.min(sum, 90), 10); // between 10 and 90
515
518
  $("#paceMarker").css({ left: position+"%" });
516
519
 
520
+ if (position > 50) {
521
+ $("#feedbackPace .obscure.left").css({ width: "50%" });
522
+ $("#feedbackPace .obscure.right").css({ width: (100-position)+"%" });
523
+ }
524
+ else {
525
+ $("#feedbackPace .obscure.right").css({ width: "50%" });
526
+ $("#feedbackPace .obscure.left").css({ width: position+"%" });
527
+ }
528
+
517
529
  if(position > 75) {
518
530
  $("#paceFast").show();
519
531
  } else {
@@ -526,6 +538,10 @@ function updatePace() {
526
538
  }
527
539
  }
528
540
 
541
+ function updateActivityCompletion(count) {
542
+ currentSlide.children('.count').text(count);
543
+ }
544
+
529
545
  // extend this function to add presenter bits
530
546
  var origGotoSlide = gotoSlide;
531
547
  gotoSlide = function (slideNum)
@@ -663,6 +679,10 @@ function postSlide() {
663
679
  $("#notes div.form.wrapper").each(function(e) {
664
680
  renderFormInterval = renderFormWatcher($(this));
665
681
  });
682
+
683
+ if(currentSlide.hasClass('activity')) {
684
+ currentSlide.children('.activityToggle').replaceWith('<span class="count">0</span>');
685
+ }
666
686
  }
667
687
  }
668
688
 
data/public/js/showoff.js CHANGED
@@ -19,6 +19,7 @@ var lastMessageGuid = 0
19
19
  var query;
20
20
  var section = 'handouts'; // default to showing handout notes for display view
21
21
  var slideStartTime = new Date().getTime()
22
+ var activityIncomplete = false; // slides won't advance when this is on
22
23
 
23
24
  var loadSlidesBool
24
25
  var loadSlidesPrefix
@@ -119,9 +120,8 @@ function setupPreso(load_slides, prefix) {
119
120
  });
120
121
 
121
122
  // Open up our control socket
122
- if(mode.track) {
123
- connectControlChannel();
124
- }
123
+ connectControlChannel();
124
+
125
125
  }
126
126
 
127
127
  function loadSlides(load_slides, prefix, reload, hard) {
@@ -183,6 +183,16 @@ function initializePresentation(prefix) {
183
183
  $('pre.highlight code').each(function(i, block) {
184
184
  try {
185
185
  hljs.highlightBlock(block);
186
+
187
+ // Highlight requested lines
188
+ block.innerHTML = block.innerHTML.split(/\r?\n/).map(function (line, i) {
189
+ if (line.indexOf('* ') === 0) {
190
+ return line.replace(/^\*(.*)$/, '<div class="highlightedLine">$1</div>');
191
+ }
192
+
193
+ return line;
194
+ }).join('\n');
195
+
186
196
  } catch(e) {
187
197
  console.log('Syntax highlighting failed on ' + $(this).closest('div.slide').attr('id'));
188
198
  console.log('Syntax highlighting failed for ' + $(this).attr('class'));
@@ -218,6 +228,13 @@ function initializePresentation(prefix) {
218
228
  }
219
229
  });
220
230
 
231
+ // The display window doesn't need the extra chrome
232
+ if(typeof(presenterView) != 'undefined') {
233
+ $('.slide.activity').removeClass('activity').children('.activityToggle').remove();
234
+ }
235
+ $('.slide.activity .activityToggle input.activity').checkboxradio();
236
+ $('.slide.activity .activityToggle input.activity').change(toggleComplete);
237
+
221
238
  // initialize mermaid, but don't render yet since the slide sizes are indeterminate
222
239
  mermaid.initialize({startOnLoad:false});
223
240
 
@@ -240,15 +257,15 @@ function zoom(presenter) {
240
257
  }
241
258
 
242
259
  // Calculate margins to center the thing *before* scaling
243
- // On mobile, we'll top align, everywhere else vertical center it.
244
- if(mobile()) {
260
+ // Vertically center on presenter, top align everywhere else
261
+ if(presenter) {
262
+ var hMargin = (hBody - hSlide) /2;
263
+ }
264
+ else {
245
265
  // (center of slide to top) - (half of the zoomed slide)
246
266
  //var hMargin = (hSlide/2 * newZoom) - (hSlide / 2);
247
267
  var hMargin = (hSlide * newZoom - hSlide) / 2;
248
268
  }
249
- else {
250
- var hMargin = (hBody - hSlide) /2;
251
- }
252
269
  var wMargin = (wBody - wSlide) /2;
253
270
 
254
271
  preso.css("margin", hMargin + "px " + wMargin + "px");
@@ -642,6 +659,21 @@ function showSlide(back_step, updatepv) {
642
659
  // copy notes to the notes field for mobile.
643
660
  postSlide();
644
661
 
662
+ // is this an activity slide that has not yet been marked complete?
663
+ if (currentSlide.hasClass('activity')) {
664
+ if (currentSlide.find('input.activity').is(":checked")) {
665
+ activityIncomplete = false;
666
+ sendActivityStatus(true);
667
+ }
668
+ else {
669
+ activityIncomplete = true;
670
+ sendActivityStatus(false);
671
+ }
672
+ }
673
+ else {
674
+ activityIncomplete = false;
675
+ }
676
+
645
677
  // make all bigly text tremendous
646
678
  currentSlide.children('.content.bigtext').bigtext();
647
679
 
@@ -730,6 +762,10 @@ function submitForm(form) {
730
762
  var submit = form.find("input[type=submit]")
731
763
  submit.attr("disabled", "disabled");
732
764
  submit.removeClass("dirty");
765
+
766
+ // stop blocking follow mode
767
+ activityIncomplete = false;
768
+ getPosition();
733
769
  });
734
770
  }
735
771
  }
@@ -758,7 +794,10 @@ function validateForm(form) {
758
794
  function enableForm(element) {
759
795
  var submit = element.closest('form').find(':submit')
760
796
  submit.removeAttr("disabled");
761
- submit.addClass("dirty")
797
+ submit.addClass("dirty");
798
+
799
+ // once a form is started, stop following the presenter
800
+ activityIncomplete = true;
762
801
  }
763
802
 
764
803
  function renderFormWatcher(element) {
@@ -996,6 +1035,9 @@ function parseMessage(data) {
996
1035
  removeQuestion(command["questionID"]);
997
1036
  break;
998
1037
 
1038
+ case 'activity':
1039
+ updateActivityCompletion(command['count']);
1040
+
999
1041
  case 'annotation':
1000
1042
  invokeAnnotation(command["type"], command["x"], command["y"]);
1001
1043
  break;
@@ -1063,6 +1105,12 @@ function sendAnnotationConfig(setting, value) {
1063
1105
  }
1064
1106
  }
1065
1107
 
1108
+ function sendActivityStatus(status) {
1109
+ if (ws.readyState == WebSocket.OPEN) {
1110
+ ws.send(JSON.stringify({ message: 'activity', slide: slidenum, status: status }));
1111
+ }
1112
+ }
1113
+
1066
1114
  function invokeAnnotation(type, x, y) {
1067
1115
  switch (type) {
1068
1116
  case 'erase':
@@ -1114,7 +1162,7 @@ function editSlide() {
1114
1162
  }
1115
1163
 
1116
1164
  function follow(slide, newIncrement) {
1117
- if (mode.follow) {
1165
+ if (mode.follow && ! activityIncomplete) {
1118
1166
  var lastSlide = slidenum;
1119
1167
  console.log("New slide: " + slide);
1120
1168
  gotoSlide(slide);
@@ -1360,6 +1408,20 @@ function getKeyName (event) {
1360
1408
  return keyName;
1361
1409
  }
1362
1410
 
1411
+ function toggleComplete() {
1412
+ if($(this).is(':checked')) {
1413
+ activityIncomplete = false;
1414
+ sendActivityStatus(true);
1415
+ if(mode.follow) {
1416
+ getPosition();
1417
+ }
1418
+ }
1419
+ else {
1420
+ activityIncomplete = true;
1421
+ sendActivityStatus(false);
1422
+ }
1423
+ }
1424
+
1363
1425
  function toggleDebug () {
1364
1426
  debugMode = !debugMode;
1365
1427
  doDebugStuff();
data/views/presenter.erb CHANGED
@@ -64,18 +64,29 @@
64
64
  </span>
65
65
  <div id="timerDisplay"></div>
66
66
  </div>
67
+
68
+ <% if @feedback then %>
67
69
  <div id="feedbackPace">
70
+ <div class="gradient"> </div>
71
+ <div class="left obscure"> </div>
72
+ <div class="right obscure"> </div>
68
73
  <span id="paceSlow">Speed Up!</span>
69
74
  <span id="paceFast">Slow Down!</span>
70
75
  <img id="paceMarker" src="<%= @asset_path %>/css/paceMarker.png" />
71
76
  </div>
77
+ <% end %>
78
+
72
79
  <div id="navigation" class="submenu"></div>
73
80
  <div id="navigationHover"></div>
81
+
82
+ <% if @feedback then %>
74
83
  <div id="questions">
75
84
  <h3>Audience Questions</h3>
76
85
  <ol id="unanswered"></ol>
77
86
  <ol id="answered"></ol>
78
87
  </div>
88
+ <% end %>
89
+
79
90
  </div>
80
91
 
81
92
  <div id="presenter">
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: showoff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.1
4
+ version: 0.17.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Chacon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-03-02 00:00:00.000000000 Z
12
+ date: 2017-03-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
@@ -165,6 +165,20 @@ dependencies:
165
165
  - - "~>"
166
166
  - !ruby/object:Gem::Version
167
167
  version: '1.3'
168
+ - !ruby/object:Gem::Dependency
169
+ name: commonmarker
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - "<="
173
+ - !ruby/object:Gem::Version
174
+ version: 0.14.4
175
+ type: :runtime
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - "<="
180
+ - !ruby/object:Gem::Version
181
+ version: 0.14.4
168
182
  - !ruby/object:Gem::Dependency
169
183
  name: mg
170
184
  requirement: !ruby/object:Gem::Requirement
@@ -212,7 +226,6 @@ files:
212
226
  - views/index.erb
213
227
  - views/onepage.erb
214
228
  - views/presenter.erb
215
- - views/stats copy.erb
216
229
  - views/stats.erb
217
230
  - public/css/TimeCircles-89ac5ae.css
218
231
  - public/css/disconnected-large.png
@@ -328,10 +341,15 @@ files:
328
341
  - public/css/highlight/vs.css
329
342
  - public/css/highlight/xcode.css
330
343
  - public/css/highlight/zenburn.css
344
+ - public/css/images/ui-icons_444444_256x240.png
345
+ - public/css/images/ui-icons_555555_256x240.png
346
+ - public/css/images/ui-icons_777620_256x240.png
347
+ - public/css/images/ui-icons_777777_256x240.png
348
+ - public/css/images/ui-icons_cc0000_256x240.png
349
+ - public/css/images/ui-icons_ffffff_256x240.png
331
350
  - public/css/jquery-ui-1.12.1.css
332
351
  - public/css/mermaid-6.0.0.css
333
352
  - public/css/onepage.css
334
- - public/css/pace.png
335
353
  - public/css/paceMarker.png
336
354
  - public/css/presenter.css
337
355
  - public/css/showoff.css
data/public/css/pace.png DELETED
Binary file
@@ -1,70 +0,0 @@
1
- <!DOCTYPE html>
2
-
3
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
- <head>
5
- <%= erb :header_mini %>
6
-
7
- <script type="text/javascript">
8
- $(document).ready(function(){ setupStats(); });
9
- </script>
10
- </head>
11
-
12
- <body id="stats">
13
- <div id="wrapper">
14
- <h1>Viewing Statistics</h1>
15
-
16
- <div id="least">
17
- <h3>Least viewed slides</h3>
18
- <% if @least.size > 0 %>
19
- <% max = @least.sort_by {|slide, time| -time}[0][1].to_f %>
20
- <% timestr = (max > 3599) ? '%H:%M:%S' : '%M:%S' %>
21
- <% @least.each do |slide, time| %>
22
- <div class="row">
23
- <span class="label"><%= slide %></span>
24
- <div class="bar" style="width: <%= (time/max)*100 %>%;"> </div>
25
- <div class="time"><%= Time.at(time).gmtime.strftime(timestr) %></div>
26
- </div>
27
- <% end %>
28
- <% end %>
29
- </div>
30
-
31
- <div id="most">
32
- <h3>Most viewed slides</h3>
33
- <% if @least.size > 0 %>
34
- <% max = @most[0][1].to_f %>
35
- <% timestr = (max > 3599) ? '%H:%M:%S' : '%M:%S' %>
36
- <% @most.each do |slide, time| %>
37
- <div class="row">
38
- <span class="label"><%= slide %></span>
39
- <div class="bar" style="width: <%= (time/max)*100 %>%;"> </div>
40
- <div class="time"><%= Time.at(time).gmtime.strftime(timestr) %></div>
41
- </div>
42
- <% end %>
43
- <% end %>
44
- </div>
45
-
46
- <div id="all">
47
- <h3>All slides</h3>
48
- <%# We reuse the max value calculated from the above step. %>
49
- <% @all.sort.map do |slide, time| %>
50
- <div class="row">
51
- <span class="label"><%= slide %></span>
52
- <div class="bar" style="width: <%= (time/max)*100 %>%;"> </div>
53
- <div class="time"><%= Time.at(time).gmtime.strftime(timestr) %></div>
54
- <% if @counter %>
55
- <div class="detail">
56
- <% @counter[slide].each do |host, count| %>
57
- <div class="row">
58
- <span class="label"><%= host %>:</span>
59
- <div class="bar" style="width: <%= (count/max)*100 %>%;"> </div>
60
- <div class="time"><%= Time.at(count).gmtime.strftime(timestr) %></div>
61
- </div>
62
- <% end %>
63
- </div>
64
- <% end %>
65
- </div>
66
- <% end %>
67
- </div>
68
- </div>
69
- </body>
70
- </html>