showoff 0.15.4 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -59,20 +59,23 @@ $(document).ready(function(){
59
59
  });
60
60
  }
61
61
 
62
- // wait until the presentation is loaded to hook up the previews.
63
- // TODO: If we decide to implement this for the audience display, we can move it later
64
- $("body").bind("showoff:loaded", function (event) {
65
- $('#navigation li a.navItem').hover(function() {
66
- var position = $(this).position();
67
- $('#navigationHover').css({top: position.top, left: position.left + $('#navigation').width() + 5})
68
- $('#navigationHover').html(slides.eq($(this).attr('rel')).html());
69
- $('#navigationHover').show();
70
- },function() {
71
- $('#navigationHover').hide();
72
- });
62
+ // set up notes resizing
63
+ $( "#notes" ).resizable({
64
+ minHeight: 0,
65
+ handles: {"n": $(".notes-grippy")}
66
+ });
67
+ $("#notes").resize(function(){
68
+ document.cookie = "notes="+$('#notes').height();
73
69
  });
74
70
 
75
71
 
72
+ // restore the UI settings
73
+ var ui = document.cookieHash['ui'];
74
+ $('#notes').height(document.cookieHash['notes']);
75
+ if(! document.cookieHash['sidebar']) {
76
+ toggleSidebar();
77
+ }
78
+
76
79
  // Hide with js so jquery knows what display property to assign when showing
77
80
  toggleAnnotations();
78
81
 
@@ -114,6 +117,7 @@ $(document).ready(function(){
114
117
  sendAnnotationConfig('fillColor', color);
115
118
  });
116
119
 
120
+ $('#statusbar .controls input').checkboxradio({icon: false });
117
121
  $('#remoteToggle').change( toggleFollower );
118
122
  $('#followerToggle').change( toggleUpdater );
119
123
  $('#annotationsToggle').change( toggleAnnotations );
@@ -258,6 +262,42 @@ function nextSlideNum(url) {
258
262
  return snum;
259
263
  }
260
264
 
265
+ // allows subsystems to pin the sidebar open. The sidebar will only hide when
266
+ // all pins have been removed.
267
+ function pinSidebar(pin) {
268
+ $('#topbar #close-sidebar').addClass('disabled');
269
+ $('#topbar #close-sidebar').removeClass('fa-rotate-90');
270
+ $('#sidebar').show();
271
+ zoom(true);
272
+
273
+ mode.pinnedSidebar = mode.pinnedSidebar || []
274
+ if (mode.pinnedSidebar.indexOf(pin) == -1) {
275
+ mode.pinnedSidebar.push(pin);
276
+ }
277
+ }
278
+
279
+ function unpinSidebar(pin) {
280
+ if (Array.isArray(mode.pinnedSidebar)) {
281
+ mode.pinnedSidebar = mode.pinnedSidebar.filter(function(item) {
282
+ return item !== pin;
283
+ });
284
+
285
+ if(mode.pinnedSidebar.length == 0) {
286
+ $('#topbar #close-sidebar').removeClass('disabled');
287
+ delete mode.pinnedSidebar;
288
+ }
289
+ }
290
+ }
291
+
292
+ function toggleSidebar() {
293
+ if (!mode.pinnedSidebar) {
294
+ $('#topbar #close-sidebar').toggleClass('fa-rotate-90');
295
+ $('#sidebar').toggle();
296
+ zoom(true);
297
+
298
+ document.cookie = "sidebar="+$('#sidebar').is(':visible');
299
+ }
300
+ }
261
301
 
262
302
  function toggleNotes() {
263
303
  mode.notes = !mode.notes;
@@ -266,9 +306,17 @@ function toggleNotes() {
266
306
  try {
267
307
  if(windowIsClosed(notesWindow)){
268
308
  notesWindow = blankStyledWindow("Showoff Notes", 'width=350,height=450', 'notes', true);
269
- window.setTimeout(postSlide, 500);
309
+ window.setTimeout(function() {
310
+ // call back and update the parent presenter if the window is closed
311
+ notesWindow.onunload = function(e) {
312
+ notesWindow.opener.toggleNotes();
313
+ };
314
+
315
+ postSlide();
316
+ }, 500);
317
+
270
318
  }
271
- $('#notesWindow').addClass('enabled');
319
+ $('#notes').addClass('hidden');
272
320
  }
273
321
  catch(e) {
274
322
  console.log('Failed to open notes window. Popup blocker?');
@@ -277,12 +325,14 @@ function toggleNotes() {
277
325
  else {
278
326
  try {
279
327
  notesWindow && notesWindow.close();
280
- $('#notesWindow').removeClass('enabled');
328
+ $('#notes').removeClass('hidden');
281
329
  }
282
330
  catch (e) {
283
331
  console.log('Notes window failed to close properly.');
284
332
  }
285
333
  }
334
+
335
+ zoom(true);
286
336
  }
287
337
 
288
338
  function blankStyledWindow(title, dimensions, classes, resizable) {
@@ -340,6 +390,9 @@ function postQuestion(question, questionID) {
340
390
 
341
391
  $("#unanswered").append(questionItem);
342
392
  updateQuestionIndicator();
393
+
394
+ // don't allow the sidebar to hid when questions exist
395
+ pinSidebar('question');
343
396
  }
344
397
 
345
398
  function removeQuestion(questionID) {
@@ -348,6 +401,10 @@ function removeQuestion(questionID) {
348
401
  .remove();
349
402
  $('#answered').append($(question));
350
403
  updateQuestionIndicator();
404
+
405
+ if($('#unanswered li').length == 0) {
406
+ unpinSidebar('question');
407
+ }
351
408
  }
352
409
 
353
410
  function updateQuestionIndicator() {
@@ -631,6 +688,9 @@ function startTimer() {
631
688
  $("#timerDisplay").show();
632
689
  $("#timerSection").addClass('open');
633
690
 
691
+ // keep the sidebar open while the timer is active
692
+ pinSidebar('timer');
693
+
634
694
  var time = parseInt( $("#timerMinutes").val() ) * 60;
635
695
  if(time) {
636
696
  $('#timerDisplay')
@@ -703,6 +763,8 @@ function toggleTimer() {
703
763
  function endTimer() {
704
764
  $('#stopTimer').val('Reset');
705
765
  $("#pauseTimer").hide();
766
+
767
+ // don't unpin yet, we don't want the timer to just wander off into the distance!
706
768
  }
707
769
 
708
770
  function stopTimer() {
@@ -716,6 +778,9 @@ function stopTimer() {
716
778
  $("#pauseTimer").hide();
717
779
  $("#timerDisplay").hide();
718
780
  $('#timerSection').removeClass();
781
+
782
+ // only unpin when the user has dismissed the timer
783
+ unpinSidebar('timer');
719
784
  }
720
785
 
721
786
  /********************
data/public/js/showoff.js CHANGED
@@ -32,6 +32,10 @@ document.cookie.split(';').forEach( function(item) {
32
32
  var pos = item.indexOf('=');
33
33
  var key = item.slice(0,pos).trim();
34
34
  var val = item.slice(pos+1).trim();
35
+ try {
36
+ val = JSON.parse(val);
37
+ }
38
+ catch(e) { }
35
39
 
36
40
  document.cookieHash[key] = val;
37
41
  });
@@ -87,6 +91,18 @@ function setupPreso(load_slides, prefix) {
87
91
  // yes, this is a global
88
92
  annotations = new Annotate();
89
93
 
94
+ // wait until the presentation is loaded to hook up the previews.
95
+ $("body").bind("showoff:loaded", function (event) {
96
+ $('#navigation li a.navItem').hover(function() {
97
+ var position = $(this).position();
98
+ $('#navigationHover').css({top: position.top, left: position.left + $('#navigation').width() + 5})
99
+ $('#navigationHover').html(slides.eq($(this).attr('rel')).html());
100
+ $('#navigationHover').show();
101
+ },function() {
102
+ $('#navigationHover').hide();
103
+ });
104
+ });
105
+
90
106
  // Open up our control socket
91
107
  if(mode.track) {
92
108
  connectControlChannel();
@@ -556,18 +572,31 @@ function showSlide(back_step, updatepv) {
556
572
  }
557
573
  }
558
574
 
559
- // Update presenter view, if we spawned one
560
- if (updatepv && 'presenterView' in window) {
575
+ // if we're a slave/display window
576
+ if('presenterView' in window) {
561
577
  var pv = window.presenterView;
562
- pv.slidenum = slidenum;
563
- pv.incrCurr = incrCurr
564
- pv.incrSteps = incrSteps
565
- pv.showSlide(true);
566
- pv.postSlide();
567
578
 
568
- pv.update();
579
+ // Update presenter view, if it's tracking us
580
+ if (updatepv) {
581
+ pv.slidenum = slidenum;
582
+ pv.incrCurr = incrCurr
583
+ pv.incrSteps = incrSteps
569
584
 
570
- }
585
+ pv.showSlide(true);
586
+ pv.postSlide();
587
+ pv.update();
588
+ }
589
+
590
+ // if the slide is marked to autoplay videos, then fire them off!
591
+ if(currentSlide.hasClass('autoplay')) {
592
+ console.log('Autoplaying ' + currentSlide.attr('id'))
593
+ setTimeout(function(){
594
+ $(currentSlide).find('video').each(function() {
595
+ $(this).get(0).play();
596
+ });
597
+ }, 1000);
598
+ }
599
+ }
571
600
 
572
601
  // Update nav
573
602
  $('.highlighted').removeClass('highlighted');
@@ -1026,7 +1055,7 @@ function feedbackActivity() {
1026
1055
 
1027
1056
  function track() {
1028
1057
  if (mode.track && ws.readyState == WebSocket.OPEN) {
1029
- var slideName = $("#slideFilename").text();
1058
+ var slideName = $("#slideFilename").text() || $("#slideFile").text(); // yey for consistency
1030
1059
  var slideEndTime = new Date().getTime();
1031
1060
  var elapsedTime = slideEndTime - slideStartTime;
1032
1061
 
@@ -1099,6 +1128,11 @@ function increment() {
1099
1128
 
1100
1129
  function prevStep(updatepv)
1101
1130
  {
1131
+ $(currentSlide).find('video').each(function() {
1132
+ console.log('Pausing videos on ' + currentSlide.attr('id'))
1133
+ $(this).get(0).pause();
1134
+ });
1135
+
1102
1136
  fireEvent("showoff:prev");
1103
1137
  track();
1104
1138
  slidenum--;
@@ -1107,6 +1141,11 @@ function prevStep(updatepv)
1107
1141
 
1108
1142
  function nextStep(updatepv)
1109
1143
  {
1144
+ $(currentSlide).find('video').each(function() {
1145
+ console.log('Pausing videos on ' + currentSlide.attr('id'))
1146
+ $(this).get(0).pause();
1147
+ });
1148
+
1110
1149
  fireEvent("showoff:next");
1111
1150
  track();
1112
1151
 
data/views/index.erb CHANGED
@@ -10,6 +10,7 @@
10
10
 
11
11
  <i id="hamburger" class="fa fa-bars fa-2x"></i>
12
12
  <div id="sidebarWrapper">
13
+ <div id="navigationHover"></div>
13
14
  <div id="feedbackSidebar" class="sideMenu">
14
15
  <img id="disconnected" src="<%= @asset_path %>/css/disconnected.png">
15
16
  <h3>Showoff Menu</h3>
data/views/presenter.erb CHANGED
@@ -5,8 +5,12 @@
5
5
  <%= erb :header %>
6
6
  <link rel="stylesheet" href="<%= @asset_path %>/css/presenter.css?v=<%= SHOWOFF_VERSION %>" type="text/css"/>
7
7
  <link href="<%= @asset_path %>/css/TimeCircles-89ac5ae.css" rel="stylesheet">
8
+ <link href="<%= @asset_path %>/css/jquery-ui-1.12.1.css" rel="stylesheet">
9
+
8
10
  <script type="text/javascript" src="<%= @asset_path %>/js/TimeCircles-89ac5ae.js"></script>
9
11
  <script type="text/javascript" src="<%= @asset_path %>/js/presenter.js?v=<%= SHOWOFF_VERSION %>"></script>
12
+ <script type="text/javascript" src="<%= @asset_path %>/js/jquery-ui-1.12.1.js"></script>
13
+
10
14
  <script type="text/javascript">
11
15
  editUrl = "<%= @edit %>";
12
16
  issueUrl = "<%= @issues %>";
@@ -16,8 +20,9 @@
16
20
  <body class="presenter">
17
21
  <%= erb :help %>
18
22
 
19
- <div id="main">
23
+ <div id="pagewrapper">
20
24
  <div id="topbar">
25
+ <a id="close-sidebar" class="fa fa-bars" aria-hidden="true" href="javascript:toggleSidebar();"></a>
21
26
  <span id="slideSource">
22
27
  <label>Source:</label>
23
28
  <% if @request.host == 'localhost' %>
@@ -40,7 +45,6 @@
40
45
  </span>
41
46
  <span>
42
47
  <a id="slaveWindow" href="javascript:toggleSlave();" title="Enable the display window.">Display Window <i class="fa fa-clone"></i></a>
43
- <a id="notesWindow" href="javascript:toggleNotes();" title="Enable the popout notes window.">Notes Window <i class="fa fa-clone"></i></a>
44
48
  </span>
45
49
  <span>
46
50
  <a id="printSlides" href="javascript:printSlides();" title="Print slides using a new window.">Print Slides <i class="fa fa-print"></i></a>
@@ -63,82 +67,88 @@
63
67
  <p><a href="javascript:chooseLayout('default');">cancel</a><input type="button" onClick="javascript:openNext();" value="Open Window" /></p>
64
68
  </div>
65
69
 
66
- <div id="center">
67
- <div id="sidebar">
68
- <div id="timerSection">
69
- <input type="button" id="pauseTimer" value="Pause" />
70
- <input type="button" id="stopTimer" value="Cancel" />
71
- <span id="timerLabel">Timer:</span>
72
- <span id="minStart">
73
- <input type="text" size="8" id="timerMinutes"/> min
74
- <input type="button" id="startTimer" value="Start" />
75
- </span>
76
- <div id="timerDisplay"></div>
70
+ <div id="main">
71
+ <div id="sidebar">
72
+ <div id="timerSection">
73
+ <input type="button" id="pauseTimer" value="Pause" />
74
+ <input type="button" id="stopTimer" value="Cancel" />
75
+ <span id="timerLabel">Timer:</span>
76
+ <span id="minStart">
77
+ <input type="text" size="8" id="timerMinutes"/> min
78
+ <input type="button" id="startTimer" value="Start" />
79
+ </span>
80
+ <div id="timerDisplay"></div>
81
+ </div>
82
+ <div id="feedbackPace">
83
+ <span id="paceSlow">Speed Up!</span>
84
+ <span id="paceFast">Slow Down!</span>
85
+ <img id="paceMarker" src="<%= @asset_path %>/css/paceMarker.png" />
86
+ </div>
87
+ <div id="navigation" class="submenu"></div>
88
+ <div id="navigationHover"></div>
89
+ <div id="questions">
90
+ <h3>Audience Questions</h3>
91
+ <ol id="unanswered"></ol>
92
+ <ol id="answered"></ol>
93
+ </div>
94
+ </div>
95
+
96
+ <div id="presenter">
97
+ <div id="frame">
98
+ <div id="preview">
99
+ <img id="disconnected" src="<%= @asset_path %>/css/disconnected-large.png" />
100
+ <div id="prevSlide" class="thumb"><div class="container"></div><h3 class="label">Previous</h3></div>
101
+ <div id="nextSlide" class="thumb"><div class="container"></div><h3 class="label">Next</h3></div>
102
+ <div id="preso">loading presentation...</div>
77
103
  </div>
78
- <div id="feedbackPace">
79
- <span id="paceSlow">Speed Up!</span>
80
- <span id="paceFast">Slow Down!</span>
81
- <img id="paceMarker" src="<%= @asset_path %>/css/paceMarker.png" />
104
+ <div id="annotationToolbar">
105
+ <label>Tools</label>
106
+ <i class="fa fa-pencil tool default active" data-action="draw" aria-hidden="true"></i>
107
+ <i class="fa fa-arrow-right tool" data-action="rightArrow" aria-hidden="true"></i>
108
+ <i class="fa fa-arrow-left tool" data-action="leftArrow" aria-hidden="true"></i>
109
+ <i class="fa fa-bullseye tool" data-action="highlight" aria-hidden="true"></i>
110
+ <i class="fa fa-eraser tool" data-action="erase" aria-hidden="true"></i>
111
+ <label>Lines</label>
112
+ <i class="fa fa-square-o lines color1 active" aria-hidden="true"></i>
113
+ <i class="fa fa-square-o lines color2" aria-hidden="true"></i>
114
+ <i class="fa fa-square-o lines color3" aria-hidden="true"></i>
115
+ <i class="fa fa-square-o lines color4" aria-hidden="true"></i>
116
+ <label>Shapes</label>
117
+ <i class="fa fa-square shapes color1" aria-hidden="true"></i>
118
+ <i class="fa fa-square shapes color2" aria-hidden="true"></i>
119
+ <i class="fa fa-square shapes color3 active" aria-hidden="true"></i>
120
+ <i class="fa fa-square shapes color4" aria-hidden="true"></i>
82
121
  </div>
83
- <div id="navigation" class="submenu"></div>
84
- <div id="navigationHover"></div>
85
122
  </div>
86
- <div id="presenter">
87
- <div id="frame">
88
- <div id="preview">
89
- <img id="disconnected" src="<%= @asset_path %>/css/disconnected-large.png" />
90
- <div id="prevSlide" class="thumb"><div class="container"></div><h3 class="label">Previous</h3></div>
91
- <div id="nextSlide" class="thumb"><div class="container"></div><h3 class="label">Next</h3></div>
92
- <div id="preso">loading presentation...</div>
93
- </div>
94
- <div id="annotationToolbar">
95
- <label>Tools</label>
96
- <i class="fa fa-pencil tool default active" data-action="draw" aria-hidden="true"></i>
97
- <i class="fa fa-arrow-right tool" data-action="rightArrow" aria-hidden="true"></i>
98
- <i class="fa fa-arrow-left tool" data-action="leftArrow" aria-hidden="true"></i>
99
- <i class="fa fa-bullseye tool" data-action="highlight" aria-hidden="true"></i>
100
- <i class="fa fa-eraser tool" data-action="erase" aria-hidden="true"></i>
101
- <label>Lines</label>
102
- <i class="fa fa-square-o lines color1 active" aria-hidden="true"></i>
103
- <i class="fa fa-square-o lines color2" aria-hidden="true"></i>
104
- <i class="fa fa-square-o lines color3" aria-hidden="true"></i>
105
- <i class="fa fa-square-o lines color4" aria-hidden="true"></i>
106
- <label>Shapes</label>
107
- <i class="fa fa-square shapes color1" aria-hidden="true"></i>
108
- <i class="fa fa-square shapes color2" aria-hidden="true"></i>
109
- <i class="fa fa-square shapes color3 active" aria-hidden="true"></i>
110
- <i class="fa fa-square shapes color4" aria-hidden="true"></i>
111
- </div>
112
- </div>
113
- <div id="statusbar">
114
- <span id="progress">
115
- Slide: <span id="slideInfo"></span>
116
- </span>
117
- <div id="debugInfo"></div>
118
- <span id="enableRemote" title="Enables tracking of other presenters.">
119
- <label for="remoteToggle">Enable Remote</label><input type="checkbox" id="remoteToggle" autocomplete="off" checked />
123
+
124
+ <div id="statusbar">
125
+ <span id="progress" class="no-mobile">
126
+ Slide: <span id="slideInfo"></span>
127
+ </span>
128
+ <div id="debugInfo"></div>
129
+
130
+ <div class="controls">
131
+ <span id="enableAnnotations" title="Enable the annotation system." class="no-mobile">
132
+ <label for="annotationsToggle">Annotations</label><input type="checkbox" id="annotationsToggle" autocomplete="off" />
120
133
  </span>
121
134
  <span id="enableFollower" title="Send slide change notifications.">
122
135
  <label for="followerToggle">Update Follower</label><input type="checkbox" id="followerToggle" autocomplete="off" checked />
123
136
  </span>
124
- <span id="enableAnnotations" title="Enable the annotation system.">
125
- <label for="annotationsToggle">Annotations</label><input type="checkbox" id="annotationsToggle" autocomplete="off" />
137
+ <span id="enableRemote" title="Enables tracking of other presenters.">
138
+ <label for="remoteToggle">Enable Remote</label><input type="checkbox" id="remoteToggle" autocomplete="off" checked />
126
139
  </span>
140
+ <a class="no-mobile fa fa-external-link-square" aria-hidden="true" href="javascript:toggleNotes();"></a>
141
+ <i class="no-mobile fa fa-bars notes-grippy ui-resizable-handle ui-resizable-n" aria-hidden="true"></i>
127
142
  </div>
128
- </div>
129
- </div>
130
143
 
131
- <div id="bottom">
144
+ </div>
132
145
  <div id="buttonNav">
133
146
  <div id="buttonPrev"><i class="fa fa-chevron-left fa-lg"></i> Previous</div><div id="buttonNext">Next <i class="fa fa-chevron-right fa-lg"></i></div>
134
147
  </div>
135
- <div id="questions">
136
- <h3>Audience Questions</h3>
137
- <ol id="unanswered"></ol>
138
- <ol id="answered"></ol>
139
- </div>
148
+
140
149
  <div id="notes"></div>
141
150
  </div>
151
+
142
152
  </div>
143
153
 
144
154
  <div id="slides" class="offscreen" <%= 'style="display:none;"' if @slides %>>