showoff 0.9.11.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/bin/showoff +4 -0
  3. data/lib/keymap.rb +30 -0
  4. data/lib/showoff/version.rb +1 -1
  5. data/lib/showoff.rb +91 -29
  6. data/public/css/highlight/agate.css +137 -0
  7. data/public/css/highlight/androidstudio.css +53 -0
  8. data/public/css/highlight/arta.css +138 -0
  9. data/public/css/highlight/ascetic.css +52 -0
  10. data/public/css/highlight/atelier-cave.dark.css +113 -0
  11. data/public/css/highlight/atelier-cave.light.css +113 -0
  12. data/public/css/highlight/atelier-dune.dark.css +94 -0
  13. data/public/css/highlight/atelier-dune.light.css +94 -0
  14. data/public/css/highlight/atelier-estuary.dark.css +113 -0
  15. data/public/css/highlight/atelier-estuary.light.css +113 -0
  16. data/public/css/highlight/atelier-forest.dark.css +94 -0
  17. data/public/css/highlight/atelier-forest.light.css +94 -0
  18. data/public/css/highlight/atelier-heath.dark.css +94 -0
  19. data/public/css/highlight/atelier-heath.light.css +94 -0
  20. data/public/css/highlight/atelier-lakeside.dark.css +94 -0
  21. data/public/css/highlight/atelier-lakeside.light.css +94 -0
  22. data/public/css/highlight/atelier-plateau.dark.css +113 -0
  23. data/public/css/highlight/atelier-plateau.light.css +113 -0
  24. data/public/css/highlight/atelier-savanna.dark.css +113 -0
  25. data/public/css/highlight/atelier-savanna.light.css +113 -0
  26. data/public/css/highlight/atelier-seaside.dark.css +94 -0
  27. data/public/css/highlight/atelier-seaside.light.css +94 -0
  28. data/public/css/highlight/atelier-sulphurpool.dark.css +94 -0
  29. data/public/css/highlight/atelier-sulphurpool.light.css +94 -0
  30. data/public/css/highlight/brown_paper.css +103 -0
  31. data/public/css/highlight/brown_papersq.png +0 -0
  32. data/public/css/highlight/codepen-embed.css +97 -0
  33. data/public/css/highlight/color-brewer.css +165 -0
  34. data/public/css/highlight/dark.css +103 -0
  35. data/public/css/highlight/darkula.css +152 -0
  36. data/public/css/highlight/default.css +155 -0
  37. data/public/css/highlight/docco.css +134 -0
  38. data/public/css/highlight/far.css +110 -0
  39. data/public/css/highlight/foundation.css +135 -0
  40. data/public/css/highlight/github-gist.css +211 -0
  41. data/public/css/highlight/github.css +123 -0
  42. data/public/css/highlight/googlecode.css +144 -0
  43. data/public/css/highlight/hybrid.css +164 -0
  44. data/public/css/highlight/idea.css +122 -0
  45. data/public/css/highlight/ir_black.css +106 -0
  46. data/public/css/highlight/kimbie.dark.css +97 -0
  47. data/public/css/highlight/kimbie.light.css +97 -0
  48. data/public/css/highlight/magula.css +120 -0
  49. data/public/css/highlight/mono-blue.css +68 -0
  50. data/public/css/highlight/monokai.css +126 -0
  51. data/public/css/highlight/monokai_sublime.css +154 -0
  52. data/public/css/highlight/obsidian.css +152 -0
  53. data/public/css/highlight/paraiso.dark.css +96 -0
  54. data/public/css/highlight/paraiso.light.css +96 -0
  55. data/public/css/highlight/pojoaque.css +106 -0
  56. data/public/css/highlight/pojoaque.jpg +0 -0
  57. data/public/css/highlight/railscasts.css +184 -0
  58. data/public/css/highlight/rainbow.css +107 -0
  59. data/public/css/highlight/school_book.css +111 -0
  60. data/public/css/highlight/school_book.png +0 -0
  61. data/public/css/highlight/solarized_dark.css +107 -0
  62. data/public/css/highlight/solarized_light.css +107 -0
  63. data/public/css/highlight/sunburst.css +161 -0
  64. data/public/css/highlight/tomorrow-night-blue.css +96 -0
  65. data/public/css/highlight/tomorrow-night-bright.css +95 -0
  66. data/public/css/highlight/tomorrow-night-eighties.css +95 -0
  67. data/public/css/highlight/tomorrow-night.css +96 -0
  68. data/public/css/highlight/tomorrow.css +93 -0
  69. data/public/css/highlight/vs.css +92 -0
  70. data/public/css/highlight/xcode.css +154 -0
  71. data/public/css/highlight/zenburn.css +118 -0
  72. data/public/css/ie8.css +4 -0
  73. data/public/css/presenter.css +5 -17
  74. data/public/css/run_code-dim.png +0 -0
  75. data/public/css/run_code.png +0 -0
  76. data/public/css/showoff.css +154 -127
  77. data/public/js/highlight.pack.js +10816 -0
  78. data/public/js/keyDictionary.json +139 -0
  79. data/public/js/presenter.js +111 -144
  80. data/public/js/showoff.js +333 -387
  81. data/views/header.erb +15 -17
  82. data/views/header_mini.erb +4 -0
  83. data/views/help.erb +79 -0
  84. data/views/index.erb +3 -22
  85. data/views/onepage.erb +27 -14
  86. data/views/presenter.erb +3 -17
  87. data/views/stats.erb +4 -4
  88. metadata +75 -62
  89. data/public/css/sh_style.css +0 -81
  90. data/public/css/tipsy.css +0 -26
  91. data/public/js/core.js +0 -79
  92. data/public/js/jquery.tipsy.js +0 -260
  93. data/public/js/onepage.js +0 -4
  94. data/public/js/sh_lang/sh_bison.min.js +0 -1
  95. data/public/js/sh_lang/sh_c.min.js +0 -1
  96. data/public/js/sh_lang/sh_caml.min.js +0 -1
  97. data/public/js/sh_lang/sh_changelog.min.js +0 -1
  98. data/public/js/sh_lang/sh_coffeescript.min.js +0 -1
  99. data/public/js/sh_lang/sh_cpp.min.js +0 -1
  100. data/public/js/sh_lang/sh_csharp.min.js +0 -1
  101. data/public/js/sh_lang/sh_css.min.js +0 -1
  102. data/public/js/sh_lang/sh_cucumber.min.js +0 -2
  103. data/public/js/sh_lang/sh_desktop.min.js +0 -1
  104. data/public/js/sh_lang/sh_diff.min.js +0 -1
  105. data/public/js/sh_lang/sh_docker.js +0 -137
  106. data/public/js/sh_lang/sh_docker.min.js +0 -1
  107. data/public/js/sh_lang/sh_erlang.min.js +0 -1
  108. data/public/js/sh_lang/sh_flex.min.js +0 -1
  109. data/public/js/sh_lang/sh_gherkin.js +0 -112
  110. data/public/js/sh_lang/sh_gherkin.min.js +0 -1
  111. data/public/js/sh_lang/sh_glsl.min.js +0 -1
  112. data/public/js/sh_lang/sh_haxe.min.js +0 -1
  113. data/public/js/sh_lang/sh_html.min.js +0 -1
  114. data/public/js/sh_lang/sh_ini.js +0 -87
  115. data/public/js/sh_lang/sh_ini.min.js +0 -87
  116. data/public/js/sh_lang/sh_java.min.js +0 -1
  117. data/public/js/sh_lang/sh_javascript.min.js +0 -1
  118. data/public/js/sh_lang/sh_javascript_dom.min.js +0 -1
  119. data/public/js/sh_lang/sh_latex.min.js +0 -1
  120. data/public/js/sh_lang/sh_ldap.min.js +0 -1
  121. data/public/js/sh_lang/sh_log.min.js +0 -1
  122. data/public/js/sh_lang/sh_lsm.min.js +0 -1
  123. data/public/js/sh_lang/sh_m4.min.js +0 -1
  124. data/public/js/sh_lang/sh_makefile.min.js +0 -1
  125. data/public/js/sh_lang/sh_oracle.min.js +0 -1
  126. data/public/js/sh_lang/sh_pascal.min.js +0 -1
  127. data/public/js/sh_lang/sh_perl.min.js +0 -1
  128. data/public/js/sh_lang/sh_php.min.js +0 -1
  129. data/public/js/sh_lang/sh_prolog.min.js +0 -1
  130. data/public/js/sh_lang/sh_properties.min.js +0 -1
  131. data/public/js/sh_lang/sh_puppet.js +0 -182
  132. data/public/js/sh_lang/sh_puppet.min.js +0 -182
  133. data/public/js/sh_lang/sh_puppet_output.js +0 -22
  134. data/public/js/sh_lang/sh_puppet_output.min.js +0 -22
  135. data/public/js/sh_lang/sh_python.min.js +0 -1
  136. data/public/js/sh_lang/sh_ruby.min.js +0 -1
  137. data/public/js/sh_lang/sh_scala.min.js +0 -1
  138. data/public/js/sh_lang/sh_sh.min.js +0 -1
  139. data/public/js/sh_lang/sh_shell.min.js +0 -1
  140. data/public/js/sh_lang/sh_slang.min.js +0 -1
  141. data/public/js/sh_lang/sh_sml.min.js +0 -1
  142. data/public/js/sh_lang/sh_spec.min.js +0 -1
  143. data/public/js/sh_lang/sh_sql.min.js +0 -1
  144. data/public/js/sh_lang/sh_tcl.min.js +0 -1
  145. data/public/js/sh_lang/sh_xml.min.js +0 -1
  146. data/public/js/sh_lang/sh_xorg.min.js +0 -1
  147. data/public/js/sh_main.min.js +0 -4
  148. data/public/js/showoffcore.js +0 -13
data/public/js/showoff.js CHANGED
@@ -16,21 +16,18 @@ var incrCode = false
16
16
  var debugMode = false
17
17
  var gotoSlidenum = 0
18
18
  var lastMessageGuid = 0
19
- var shiftKeyActive = false
20
19
  var query
21
20
  var slideStartTime = new Date().getTime()
22
21
 
23
- var questionPrompt = 'Ask a question...'
24
- var feedbackPrompt = 'Why?...'
25
-
26
22
  var loadSlidesBool
27
23
  var loadSlidesPrefix
28
24
 
29
- var mode = { track: true, follow: false };
25
+ var keycode_dictionary,
26
+ keycode_shifted_keys;
27
+
28
+ var mode = { track: true, follow: true };
30
29
 
31
- $(document).on('click', '.execute .sh_javascript code', executeCode);
32
- $(document).on('click', '.execute .sh_ruby code', executeRuby);
33
- $(document).on('click','.execute .sh_coffeescript code', executeCoffee);
30
+ $(document).on('click', 'code.execute', executeCode);
34
31
 
35
32
  function setupPreso(load_slides, prefix) {
36
33
  if (preso_started)
@@ -48,14 +45,12 @@ function setupPreso(load_slides, prefix) {
48
45
  loadSlidesPrefix = prefix || '/'
49
46
  loadSlides(loadSlidesBool, loadSlidesPrefix)
50
47
 
48
+ loadKeyDictionaries();
49
+
51
50
  doDebugStuff()
52
51
 
53
52
  // bind event handlers
54
- document.onkeydown = keyDown
55
- document.onkeyup = keyUp
56
- /* window.onresize = resized; */
57
- /* window.onscroll = scrolled; */
58
- /* window.onunload = unloaded; */
53
+ toggleKeybinding('on');
59
54
 
60
55
  $('#preso').addSwipeEvents().
61
56
  bind('tap', swipeLeft). // next
@@ -79,13 +74,11 @@ function setupPreso(load_slides, prefix) {
79
74
  $("#feedbackWrapper").hover(
80
75
  function() {
81
76
  $('#feedbackSidebar').show();
82
- document.onkeydown = null;
83
- document.onkeyup = null;
77
+ toggleKeybinding();
84
78
  },
85
79
  function() {
86
80
  $('#feedbackSidebar').hide();
87
- document.onkeydown = keyDown;
88
- document.onkeyup = keyUp;
81
+ toggleKeybinding();
89
82
  }
90
83
  );
91
84
 
@@ -97,11 +90,6 @@ function setupPreso(load_slides, prefix) {
97
90
  });
98
91
  $("#editSlide").click(function() { editSlide(); });
99
92
 
100
- $("textarea#question").val(questionPrompt);
101
- $("textarea#feedback").val(feedbackPrompt);
102
- $("textarea#question").focus(function() { clearIf($(this), questionPrompt) });
103
- $("textarea#feedback").focus(function() { clearIf($(this), feedbackPrompt) });
104
-
105
93
  // Open up our control socket
106
94
  if(mode.track) {
107
95
  connectControlChannel();
@@ -129,13 +117,17 @@ function loadSlides(load_slides, prefix) {
129
117
  }
130
118
  }
131
119
 
120
+ function loadKeyDictionaries () {
121
+ $.getJSON('/js/keyDictionary.json', function(data) {
122
+ keycode_dictionary = data['keycodeDictionary'];
123
+ keycode_shifted_keys = data['shiftedKeyDictionary'];
124
+ });
125
+ }
126
+
132
127
  function initializePresentation(prefix) {
133
128
  // unhide for height to work in static mode
134
129
  $("#slides").show();
135
130
 
136
- //center slides offscreen
137
- centerSlides($('#slides > .slide'))
138
-
139
131
  //copy into presentation area
140
132
  $("#preso").empty()
141
133
  $('#slides > .slide').appendTo($("#preso"))
@@ -150,7 +142,7 @@ function initializePresentation(prefix) {
150
142
  })
151
143
 
152
144
  setupMenu()
153
- setupStyleMenu()
145
+
154
146
  if (slidesLoaded) {
155
147
  showSlide()
156
148
  } else {
@@ -159,11 +151,16 @@ function initializePresentation(prefix) {
159
151
  }
160
152
  setupSlideParamsCheck();
161
153
 
162
- try {
163
- sh_highlightDocument('/js/sh_lang/', '.min.js')
164
- } catch(e) {
165
- sh_highlightDocument();
166
- }
154
+
155
+ $('pre.highlight code').each(function(i, block) {
156
+ try {
157
+ hljs.highlightBlock(block);
158
+ } catch(e) {
159
+ console.log('Syntax highlighting failed on ' + $(this).closest('div.slide').attr('id'));
160
+ console.log('Syntax highlighting failed for ' + $(this).attr('class'));
161
+ console.log(e);
162
+ }
163
+ });
167
164
 
168
165
  $(".content form").submit(function(e) {
169
166
  e.preventDefault();
@@ -172,12 +169,10 @@ function initializePresentation(prefix) {
172
169
 
173
170
  // suspend hotkey handling
174
171
  $(".content form :input").focus( function() {
175
- document.onkeydown = null;
176
- document.onkeyup = null;
172
+ toggleKeybinding();
177
173
  });
178
174
  $(".content form :input").blur( function() {
179
- document.onkeydown = keyDown;
180
- document.onkeyup = keyUp;
175
+ toggleKeybinding();
181
176
  });
182
177
 
183
178
  $(".content form :input").change(function(e) {
@@ -220,22 +215,6 @@ function zoom()
220
215
  }
221
216
  }
222
217
 
223
- function centerSlides(slides) {
224
- slides.each(function(s, slide) {
225
- centerSlide(slide)
226
- })
227
- }
228
-
229
- function centerSlide(slide) {
230
- var slide_content = $(slide).find(".content").first()
231
- var height = slide_content.height()
232
- var mar_top = (0.5 * parseFloat($(slide).height())) - (0.5 * parseFloat(height))
233
- if (mar_top < 0) {
234
- mar_top = 0
235
- }
236
- slide_content.css('margin-top', mar_top)
237
- }
238
-
239
218
  function setupMenu() {
240
219
  $('#navmenu').hide();
241
220
 
@@ -459,13 +438,6 @@ function showIncremental(incr)
459
438
  }
460
439
  }
461
440
 
462
- function clearIf(elem, val) {
463
- console.log(elem.val());
464
- console.log(val);
465
- if(elem.val() == val ) { elem.val(''); }
466
- }
467
-
468
-
469
441
  // form handling
470
442
  function submitForm(form) {
471
443
  if(validateForm(form)) {
@@ -700,14 +672,12 @@ function sendPace(pace) {
700
672
 
701
673
  function askQuestion(question) {
702
674
  ws.send(JSON.stringify({ message: 'question', question: question}));
703
- $("textarea#question").val(questionPrompt);
704
675
  feedbackActivity();
705
676
  }
706
677
 
707
678
  function sendFeedback(rating, feedback) {
708
679
  var slide = $("#slideFilename").text();
709
680
  ws.send(JSON.stringify({ message: 'feedback', rating: rating, feedback: feedback, slide: slide}));
710
- $("textarea#feedback").val(feedbackPrompt);
711
681
  $("input:radio[name=rating]:checked").attr('checked', false);
712
682
  feedbackActivity();
713
683
  }
@@ -802,6 +772,10 @@ function doDebugStuff()
802
772
 
803
773
  function blankScreen()
804
774
  {
775
+ try {
776
+ slaveWindow.blankScreen();
777
+ }
778
+ catch (e) {
805
779
  if ($('#screenblanker').length) { // if #screenblanker exists
806
780
  $('#screenblanker').slideUp('normal', function() {
807
781
  $('#screenblanker').remove();
@@ -810,6 +784,7 @@ function blankScreen()
810
784
  $('body').prepend('<div id="screenblanker"></div>');
811
785
  $('#screenblanker').slideDown();
812
786
  }
787
+ }
813
788
  }
814
789
 
815
790
  var notesMode = false
@@ -836,149 +811,121 @@ function toggleFollow()
836
811
  }
837
812
  }
838
813
 
839
- function executeAnyCode()
840
- {
841
- var $jsCode = $('.execute .sh_javascript code:visible')
842
- if ($jsCode.length > 0) {
843
- executeCode.call($jsCode);
844
- }
845
- var $rubyCode = $('.execute .sh_ruby code:visible')
846
- if ($rubyCode.length > 0) {
847
- executeRuby.call($rubyCode);
848
- }
849
- var $coffeeCode = $('.execute .sh_coffeescript code:visible')
850
- if ($coffeeCode.length > 0) {
851
- executeCoffee.call($coffeeCode);
852
- }
853
- }
854
-
855
814
  function debug(data)
856
815
  {
857
816
  $('#debugInfo').text(data)
858
817
  }
859
818
 
860
- // See e.g. http://www.quirksmode.org/js/keys.html for keycodes
861
- function keyDown(event)
862
- {
863
- var key = event.keyCode;
819
+ function toggleKeybinding (setting) {
820
+ if (document.onkeydown === null || setting === 'on') {
821
+ if (typeof presenterKeyDown === 'function') {
822
+ document.onkeydown = presenterKeyDown;
823
+ } else {
824
+ document.onkeydown = keyDown;
825
+ }
826
+ } else {
827
+ document.onkeydown = null;
828
+ }
829
+ }
864
830
 
865
- if (event.ctrlKey || event.altKey || event.metaKey)
866
- return true;
831
+ function keyDown(event){
832
+ var key = event.keyCode;
867
833
 
868
- debug('keyDown: ' + key)
834
+ debug('keyDown: ' + key);
835
+ // avoid overriding browser commands
836
+ if (event.ctrlKey || event.altKey || event.metaKey) {
837
+ return true;
838
+ }
869
839
 
870
- if (key >= 48 && key <= 57) // 0 - 9
871
- {
872
- gotoSlidenum = gotoSlidenum * 10 + (key - 48);
873
- return true;
874
- }
840
+ switch(getAction(event)) {
841
+ case 'DEBUG': toggleDebug(); break;
842
+ case 'PREV': prevStep(); break;
843
+ case 'NEXT': nextStep(); break;
844
+ case 'RELOAD': reloadSlides(); break;
845
+ case 'CONTENTS': toggleContents(); break;
846
+ case 'HELP': toggleHelp(); break;
847
+ case 'BLANK': blankScreen(); break;
848
+ case 'FOOTER': toggleFooter(); break;
849
+ case 'FOLLOW': toggleFollow(); break;
850
+ case 'NOTES': toggleNotes(); break;
851
+ case 'CLEAR': removeResults(); break;
852
+ case 'PAUSE': togglePause(); break;
853
+ case 'PRESHOW': togglePreShow(); break;
854
+ case 'EXECUTE':
855
+ debug('executeCode');
856
+ executeVisibleCodeBlock();
857
+ break;
858
+ default:
859
+ switch (key) {
860
+ case 48: // 0
861
+ case 49: // 1
862
+ case 50: // 2
863
+ case 51: // 3
864
+ case 52: // 4
865
+ case 53: // 5
866
+ case 54: // 6
867
+ case 55: // 7
868
+ case 56: // 8
869
+ case 57: // 9
870
+ // concatenate numbers from previous keypress events
871
+ gotoSlidenum = gotoSlidenum * 10 + (key - 48);
872
+ break;
873
+ case 13: // enter/return
874
+ // check for a combination of numbers from previous keypress events
875
+ if (gotoSlidenum > 0) {
876
+ debug('go to ' + gotoSlidenum);
877
+ slidenum = gotoSlidenum - 1;
878
+ showSlide(true);
879
+ gotoSlidenum = 0;
880
+ }
881
+ break;
882
+ default:
883
+ break;
884
+ }
885
+ break;
886
+ }
887
+ return true;
888
+ }
875
889
 
876
- if (key == 13) {
877
- if (gotoSlidenum > 0) {
878
- debug('go to ' + gotoSlidenum);
879
- slidenum = gotoSlidenum - 1;
880
- showSlide(true);
881
- gotoSlidenum = 0;
882
- } else {
883
- debug('executeCode');
884
- executeAnyCode();
885
- }
886
- }
890
+ function getAction (event) {
891
+ return keymap[getKeyName(event)];
892
+ }
887
893
 
894
+ function getKeyName (event) {
895
+ var keyName = keycode_dictionary[event.keyCode];
896
+ if (event.shiftKey && keyName !== undefined) {
897
+ // Check for non-alpha characters first, because no idea what toUpperCase will do to those
898
+ if (keycode_shifted_keys[keyName] !== undefined) {
899
+ keyName = keycode_shifted_keys[keyName];
900
+ } else {
901
+ keyName = keyName.toUpperCase();
902
+ }
903
+ }
904
+ return keyName;
905
+ }
888
906
 
889
- if (key == 16) // shift key
890
- {
891
- shiftKeyActive = true;
892
- }
907
+ function toggleDebug () {
908
+ debugMode = !debugMode;
909
+ doDebugStuff();
910
+ }
893
911
 
894
- if (key == 32) // space bar
895
- {
896
- if (shiftKeyActive) {
897
- prevStep()
898
- } else {
899
- nextStep()
900
- }
901
- }
902
- else if (key == 68) // 'd' for debug
903
- {
904
- debugMode = !debugMode
905
- doDebugStuff()
906
- }
907
- else if (key == 37 || key == 33 || key == 38) // Left arrow, page up, or up arrow
908
- {
909
- prevStep()
910
- }
911
- else if (key == 39 || key == 34 || key == 40) // Right arrow, page down, or down arrow
912
- {
913
- nextStep()
914
- }
915
- else if (key == 82) // R for reload
916
- {
917
- if (confirm('really reload slides?')) {
918
- loadSlides(loadSlidesBool, loadSlidesPrefix)
919
- showSlide()
920
- }
921
- }
922
- else if (key == 84 || key == 67) // T or C for table of contents
923
- {
924
- $('#navmenu').toggle().trigger('click')
925
- }
926
- else if (key == 83) // 's' for style
927
- {
928
- $('#stylemenu').toggle().trigger('click')
929
- }
930
- else if (key == 90 || key == 191) // z or ? for help
931
- {
932
- $('#help').toggle()
933
- }
934
- else if (key == 66) // b for blank, also what kensington remote "stop" button sends
935
- {
936
- blankScreen()
937
- }
938
- else if (key == 70) // f for footer
939
- {
940
- toggleFooter()
941
- }
942
- else if (key == 71) // g for follow mode
943
- {
944
- toggleFollow()
945
- }
946
- else if (key == 76) // l for leader mode
947
- {
948
- toggleLeader()
949
- }
950
- else if (key == 78) // 'n' for notes
951
- {
952
- toggleNotes()
953
- }
954
- else if (key == 27) // esc
955
- {
956
- removeResults();
957
- }
958
- else if (key == 80) // 'p' for preshow, 'P' for pause
959
- {
960
- if (shiftKeyActive) {
961
- togglePause();
962
- }
963
- else {
964
- togglePreShow();
965
- }
966
- }
967
- return true
912
+ function reloadSlides () {
913
+ if (confirm('Are you sure you want to reload the slides?')) {
914
+ loadSlides(loadSlidesBool, loadSlidesPrefix);
915
+ showSlide();
916
+ }
968
917
  }
969
918
 
970
- function toggleFooter()
971
- {
919
+ function toggleFooter() {
972
920
  $('#footer').toggle()
973
921
  }
974
922
 
975
- function keyUp(event) {
976
- var key = event.keyCode;
977
- debug('keyUp: ' + key);
978
- if (key == 16) // shift key
979
- {
980
- shiftKeyActive = false;
981
- }
923
+ function toggleHelp () {
924
+ $('#help').toggle();
925
+ }
926
+
927
+ function toggleContents () {
928
+ $('#navmenu').toggle().trigger('click');
982
929
  }
983
930
 
984
931
  function swipeLeft() {
@@ -1036,153 +983,245 @@ function ListMenuItem(t, s)
1036
983
 
1037
984
  var removeResults = function() {
1038
985
  $('.results').remove();
986
+
987
+ // if we're a presenter, mirror this on the display window
988
+ try { slaveWindow.removeResults() } catch (e) {};
1039
989
  };
1040
990
 
1041
991
  var print = function(text) {
1042
992
  removeResults();
1043
- var _results = $('<div>').addClass('results').html($.print(text, {max_string:500}));
993
+ var _results = $('<div>').addClass('results').html('<pre>'+$.print(text, {max_string:500})+'</pre>');
1044
994
  $('body').append(_results);
1045
995
  _results.click(removeResults);
996
+
997
+ // if we're a presenter, mirror this on the display window
998
+ try { slaveWindow.print(text) } catch (e) {};
1046
999
  };
1047
1000
 
1048
- function executeCode () {
1049
- result = null;
1050
- var codeDiv = $(this);
1051
- codeDiv.addClass("executing");
1052
- eval(codeDiv.text());
1053
- setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
1054
- if (result != null) print(result);
1055
- }
1056
-
1057
- function executeRuby () {
1058
- var codeDiv = $(this);
1059
- codeDiv.addClass("executing");
1060
- $.get('/eval_ruby', {code: codeDiv.text()}, function(result) {
1061
- if (result != null) print(result);
1062
- codeDiv.removeClass("executing");
1063
- });
1001
+ // Execute the first visible executable code block
1002
+ function executeVisibleCodeBlock()
1003
+ {
1004
+ var code = $('code.execute:visible')
1005
+ if (code.length > 0) {
1006
+ // make the code block available as $(this) object
1007
+ executeCode.call(code[0]);
1008
+ }
1064
1009
  }
1065
1010
 
1066
- function executeCoffee() {
1067
- result = null;
1068
- var codeDiv = $(this);
1069
- codeDiv.addClass("executing");
1070
- // Coffeescript encapsulates everything, so result must be attached to window.
1071
- var code = codeDiv.text() + ';window.result=result;'
1072
- eval(CoffeeScript.compile(code));
1073
- setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
1074
- if (result != null) print(result);
1011
+ // determine which code handler to call and execute code sample
1012
+ function executeCode() {
1013
+ var codeDiv = $(this);
1014
+
1015
+ try {
1016
+ var lang = codeDiv.attr("class").match(/\blanguage-(\w+)/)[1];
1017
+ switch(lang) {
1018
+ case 'javascript':
1019
+ case 'coffeescript':
1020
+ executeLocalCode(lang, codeDiv);
1021
+ break;
1022
+ default:
1023
+ executeRemoteCode(lang, codeDiv)
1024
+ break;
1025
+ }
1026
+ }
1027
+ catch(e) {
1028
+ debug('No code block to execute: ' + codeDiv.attr('class'));
1029
+ };
1030
+ }
1031
+
1032
+ // any code that can be run directly in the browser
1033
+ function executeLocalCode(lang, codeDiv) {
1034
+ var result = null;
1035
+ var codeDiv = $(this);
1036
+
1037
+ setExecutionSignal(true, codeDiv);
1038
+ setTimeout(function() { setExecutionSignal(false, codeDiv);}, 1000 );
1039
+
1040
+ try {
1041
+ switch(lang) {
1042
+ case 'javascript':
1043
+ result = eval(codeDiv.text());
1044
+ break;
1045
+ case 'coffeescript':
1046
+ result = eval(CoffeeScript.compile(codeDiv.text(), {bare: true}));
1047
+ break;
1048
+ default:
1049
+ result = 'No local exec handler for ' + lang;
1050
+ }
1051
+ }
1052
+ catch(e) {
1053
+ result = e.message;
1054
+ };
1055
+ if (result != null) print(result);
1056
+ }
1057
+
1058
+ // request the server to execute a code block by path and index
1059
+ function executeRemoteCode(lang, codeDiv) {
1060
+ var slide = codeDiv.closest('div.content');
1061
+ var index = slide.find('code.execute').index(codeDiv);
1062
+ var path = slide.attr('ref');
1063
+
1064
+ setExecutionSignal(true, codeDiv);
1065
+ $.get('/execute/'+lang, {path: path, index: index}, function(result) {
1066
+ if (result != null) print(result);
1067
+ setExecutionSignal(false, codeDiv);
1068
+ });
1069
+ }
1070
+
1071
+ // Provide visual indication that a block of code is running
1072
+ function setExecutionSignal(status, codeDiv) {
1073
+ if (status === true) {
1074
+ codeDiv.addClass("executing");
1075
+ }
1076
+ else {
1077
+ codeDiv.removeClass("executing");
1078
+ }
1079
+
1080
+ // if we're a presenter, mirror this on the display window
1081
+ try {
1082
+ var id = codeDiv.closest('div.slide').attr('id');
1083
+ var index = $('div.slide#'+id+' code.execute').index(codeDiv);
1084
+ var code = slaveWindow.$('div.slide#'+id+' code.execute').eq(index)
1085
+
1086
+ if (status === true) {
1087
+ code.addClass("executing");
1088
+ }
1089
+ else {
1090
+ code.removeClass("executing");
1091
+ }
1092
+ } catch (e) {};
1075
1093
  }
1076
1094
 
1077
1095
  /********************
1078
1096
  PreShow Code
1079
1097
  ********************/
1080
1098
 
1081
- var preshow_seconds = 0;
1082
- var preshow_secondsLeft = 0;
1083
- var preshow_secondsPer = 8;
1084
- var preshow_running = false;
1085
- var preshow_timerRunning = false;
1086
- var preshow_current = 0;
1087
- var preshow_images;
1088
- var preshow_imagesTotal = 0;
1089
- var preshow_des = null;
1099
+
1100
+ var preshow_stop = null;
1101
+ var preshow_secondsPer = 8;
1102
+
1103
+ var preshow_current = 0;
1104
+ var preshow_images = null;
1105
+ var preshow_imagesTotal = 0;
1106
+ var preshow_des = null;
1090
1107
 
1091
1108
  function togglePreShow() {
1092
- if(preshow_running) {
1093
- stopPreShow()
1094
- } else {
1095
- var minutes = prompt("Minutes from now to start")
1096
-
1097
- if (preshow_secondsLeft = parseFloat(minutes) * 60) {
1098
- toggleFooter()
1099
- $.getJSON("preshow_files", false, function(data) {
1100
- $('#preso').after("<div id='preshow'></div><div id='tips'></div><div id='preshow_timer'></div>")
1101
- $.each(data, function(i, n) {
1102
- if(n == "preshow.json") {
1103
- // has a descriptions file
1104
- $.getJSON("/file/_preshow/preshow.json", false, function(data) {
1105
- preshow_des = data
1106
- })
1107
- } else {
1108
- $('#preshow').append('<img ref="' + n + '" src="/file/_preshow/' + n + '"/>')
1109
- }
1110
- })
1111
- startPreShow()
1112
- })
1113
- }
1114
- }
1109
+ // The slave window updates this flag, which seems backwards except that the
1110
+ // slave determines when to finish preshow.
1111
+ if(preshow_stop) {
1112
+ try {
1113
+ slaveWindow.stopPreShow();
1114
+ }
1115
+ catch (e) {
1116
+ stopPreShow();
1117
+ }
1118
+
1119
+ } else {
1120
+ var seconds = parseFloat(prompt("Minutes from now to start") * 60);
1121
+
1122
+ try {
1123
+ slaveWindow.setupPreShow(seconds);
1124
+ }
1125
+ catch (e) {
1126
+ setupPreShow(seconds);
1127
+ }
1128
+ }
1129
+ }
1130
+
1131
+ function setupPreShow(seconds) {
1132
+ preshow_stop = secondsFromNow(seconds);
1133
+ try { presenterView.preshow_stop = preshow_stop } catch (e) {}
1134
+
1135
+ // footer styling looks icky. Hide it for now.
1136
+ $('#footer').hide();
1137
+
1138
+ $.getJSON("preshow_files", false, function(data) {
1139
+ $('#preso').after("<div id='preshow'></div><div id='tips'></div><div id='preshow_timer'></div>");
1140
+ $.each(data, function(i, n) {
1141
+ if(n == "preshow.json") {
1142
+ // has a descriptions file
1143
+ $.getJSON("/file/_preshow/preshow.json", false, function(data) {
1144
+ preshow_des = data;
1145
+ })
1146
+ } else {
1147
+ $('#preshow').append('<img ref="' + n + '" src="/file/_preshow/' + n + '"/>');
1148
+ }
1149
+ })
1150
+ preshow_images = $('#preshow > img');
1151
+ preshow_imagesTotal = preshow_images.size();
1152
+
1153
+ startPreShow();
1154
+ });
1115
1155
  }
1116
1156
 
1117
1157
  function startPreShow() {
1118
- if (!preshow_running) {
1119
- preshow_running = true
1120
- preshow_seconds = 0
1121
- preshow_images = $('#preshow > img')
1122
- preshow_imagesTotal = preshow_images.size()
1123
- nextPreShowImage()
1124
-
1125
- if(!preshow_timerRunning) {
1126
- setInterval(function() {
1127
- preshow_timerRunning = true
1128
- if (!preshow_running) { return }
1129
- preshow_seconds++
1130
- preshow_secondsLeft--
1131
- if (preshow_secondsLeft < 0) {
1132
- stopPreShow()
1133
- }
1134
- if (preshow_seconds == preshow_secondsPer) {
1135
- preshow_seconds = 0
1136
- nextPreShowImage()
1137
- }
1138
- addPreShowTips()
1139
- }, 1000)
1140
- }
1141
- }
1158
+ nextPreShowImage();
1159
+
1160
+ var nextImage = secondsFromNow(preshow_secondsPer);
1161
+ var interval = setInterval(function() {
1162
+ var now = new Date();
1163
+
1164
+ if (now > preshow_stop) {
1165
+ clearInterval(interval);
1166
+ stopPreShow();
1167
+ } else {
1168
+ if (now > nextImage) {
1169
+ nextImage = secondsFromNow(preshow_secondsPer);
1170
+ nextPreShowImage();
1171
+ }
1172
+ var secondsLeft = Math.floor((preshow_stop.getTime() - now.getTime()) / 1000);
1173
+ addPreShowTips(secondsLeft);
1174
+ }
1175
+ }, 1000)
1142
1176
  }
1143
1177
 
1144
- function addPreShowTips() {
1145
- time = secondsToTime(preshow_secondsLeft)
1146
- $('#preshow_timer').text('Resuming in: ' + time)
1147
- var des = preshow_des && preshow_des[tmpImg.attr("ref")]
1178
+ function addPreShowTips(secondsLeft) {
1179
+ $('#preshow_timer').text('Resuming in: ' + secondsToTime(secondsLeft));
1180
+ var des = preshow_des && preshow_des[tmpImg.attr("ref")];
1148
1181
  if(des) {
1149
- $('#tips').show()
1150
- $('#tips').text(des)
1182
+ $('#tips').show();
1183
+ $('#tips').text(des);
1151
1184
  } else {
1152
- $('#tips').hide()
1185
+ $('#tips').hide();
1153
1186
  }
1154
1187
  }
1155
1188
 
1189
+ function secondsFromNow(seconds) {
1190
+ var now = new Date();
1191
+ now.setTime(now.getTime() + seconds * 1000);
1192
+ return now;
1193
+ }
1194
+
1156
1195
  function secondsToTime(sec) {
1157
- min = Math.floor(sec / 60)
1158
- sec = sec - (min * 60)
1196
+ var min = Math.floor(sec / 60);
1197
+ sec = sec - (min * 60);
1159
1198
  if(sec < 10) {
1160
- sec = "0" + sec
1199
+ sec = "0" + sec;
1161
1200
  }
1162
- return min + ":" + sec
1201
+ return min + ":" + sec;
1163
1202
  }
1164
1203
 
1165
1204
  function stopPreShow() {
1166
- preshow_running = false
1205
+ try { presenterView.preshow_stop = null } catch (e) {}
1206
+ preshow_stop = null;
1167
1207
 
1168
- $('#preshow').remove()
1169
- $('#tips').remove()
1170
- $('#preshow_timer').remove()
1208
+ $('#preshow').remove();
1209
+ $('#tips').remove();
1210
+ $('#preshow_timer').remove();
1171
1211
 
1172
- toggleFooter()
1173
1212
  loadSlides(loadSlidesBool, loadSlidesPrefix);
1174
1213
  }
1175
1214
 
1176
1215
  function nextPreShowImage() {
1177
- preshow_current += 1
1216
+ preshow_current += 1;
1178
1217
  if((preshow_current + 1) > preshow_imagesTotal) {
1179
- preshow_current = 0
1218
+ preshow_current = 0;
1180
1219
  }
1181
1220
 
1182
- $("#preso").empty()
1183
- tmpImg = preshow_images.eq(preshow_current).clone()
1184
- $(tmpImg).attr('width', '1020')
1185
- $("#preso").html(tmpImg)
1221
+ $("#preso").empty();
1222
+ tmpImg = preshow_images.eq(preshow_current).clone();
1223
+ $(tmpImg).attr('width', '1020');
1224
+ $("#preso").html(tmpImg);
1186
1225
  }
1187
1226
 
1188
1227
  /********************
@@ -1190,107 +1229,14 @@ function nextPreShowImage() {
1190
1229
  ********************/
1191
1230
 
1192
1231
  function togglePause() {
1193
- $("#pauseScreen").toggle();
1194
- }
1195
-
1196
- /********************
1197
- Style-Picker Code
1198
- ********************/
1199
-
1200
- function styleChoiceTags() {
1201
- return $('link[rel*="stylesheet"][href*="file/"]');
1202
- }
1203
-
1204
- function styleChoices() {
1205
- return $.map(styleChoiceTags(), function(el) { return styleChoiceString(el.href); });
1206
- }
1207
-
1208
- function styleChoiceString(href) {
1209
- var parts = href.split('/');
1210
- var file = parts[parts.length - 1];
1211
- var choice = file.replace(/\.css$/, '');
1212
-
1213
- return choice;
1214
- }
1215
-
1216
- function getCurrentStyle()
1217
- {
1218
- var current = '';
1219
-
1220
- styleChoiceTags().each(function (i, el) {
1221
- if (el.rel == 'stylesheet') {
1222
- current = el.href;
1223
- }
1224
- });
1225
-
1226
- return styleChoiceString(current);
1227
- }
1228
-
1229
- function setCurrentStyle(style, prop)
1230
- {
1231
- styleChoiceTags().each(function (i, el) {
1232
- el.rel = 'alternate stylesheet';
1233
-
1234
- if (styleChoiceString(el.href) == style) {
1235
- el.rel = 'stylesheet';
1236
- }
1237
- });
1238
-
1239
- if (prop) {
1240
- if ('presenterView' in window) {
1241
- var pv = window.presenterView;
1242
- pv.setCurrentStyle(style, false);
1243
- }
1244
- }
1245
- }
1246
-
1247
- function setupStyleMenu() {
1248
- $('#stylemenu').hide();
1249
-
1250
- var menu = new StyleListMenu();
1251
- styleChoices().each(function(s) {
1252
- menu.addItem(s)
1253
- })
1254
-
1255
- $('#stylepicker').html(menu.getList())
1256
- $('#stylemenu').menu({
1257
- content: $('#stylepicker').html(),
1258
- flyOut: true
1259
- });
1260
- }
1261
-
1262
- function StyleListMenu()
1263
- {
1264
- this.typeName = 'StyleListMenu'
1265
- this.items = new Array();
1266
- this.addItem = function (key) {
1267
- this.items[key] = new StyleListMenuItem(key)
1232
+ try {
1233
+ slaveWindow.togglePause();
1268
1234
  }
1269
- this.getList = function() {
1270
- var newMenu = $("<ul>")
1271
- for(var i in this.items) {
1272
- var item = this.items[i]
1273
- var domItem = $("<li>")
1274
- if (item.textName != undefined) {
1275
- choice = $("<a onclick=\"setCurrentStyle('" + item.textName + "', true); $('#stylemenu').hide();\" href=\"#\">" + item.textName + "</a>")
1276
- domItem.append(choice)
1277
- newMenu.append(domItem)
1278
- }
1279
- }
1280
- return newMenu
1235
+ catch (e) {
1236
+ $("#pauseScreen").toggle();
1281
1237
  }
1282
1238
  }
1283
1239
 
1284
- function StyleListMenuItem(t)
1285
- {
1286
- this.typeName = "StyleListMenuItem"
1287
- this.textName = t
1288
- }
1289
- /********************
1290
- End Style-Picker Code
1291
- ********************/
1292
-
1293
-
1294
1240
  /********************
1295
1241
  Stats page
1296
1242
  ********************/