parade 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +542 -0
  3. data/Rakefile +15 -0
  4. data/bin/parade +138 -0
  5. data/lib/parade.rb +43 -0
  6. data/lib/parade/commands/commands.rb +84 -0
  7. data/lib/parade/commands/generate_outline.rb +34 -0
  8. data/lib/parade/commands/generate_presentation.rb +34 -0
  9. data/lib/parade/commands/generate_rackup.rb +32 -0
  10. data/lib/parade/commands/html_output.rb +47 -0
  11. data/lib/parade/commands/render_from_template.rb +50 -0
  12. data/lib/parade/commands/static_html.rb +38 -0
  13. data/lib/parade/commands/static_pdf.rb +39 -0
  14. data/lib/parade/commands/unknown.rb +23 -0
  15. data/lib/parade/features/live_ruby.rb +18 -0
  16. data/lib/parade/features/pdf_presentation.rb +24 -0
  17. data/lib/parade/features/preshow.rb +11 -0
  18. data/lib/parade/helpers/encode_image.rb +24 -0
  19. data/lib/parade/helpers/template_generator.rb +130 -0
  20. data/lib/parade/metadata.rb +73 -0
  21. data/lib/parade/metadata/assignment.rb +38 -0
  22. data/lib/parade/metadata/css_classes.rb +22 -0
  23. data/lib/parade/metadata/html_id.rb +35 -0
  24. data/lib/parade/metadata/template.rb +31 -0
  25. data/lib/parade/parsers/dsl.rb +138 -0
  26. data/lib/parade/parsers/dsl_file_parser.rb +17 -0
  27. data/lib/parade/parsers/json_file_parser.rb +67 -0
  28. data/lib/parade/parsers/markdown_image_paths.rb +44 -0
  29. data/lib/parade/parsers/markdown_slide_splitter.rb +63 -0
  30. data/lib/parade/parsers/presentation_directory_parser.rb +36 -0
  31. data/lib/parade/parsers/presentation_file_parser.rb +27 -0
  32. data/lib/parade/parsers/presentation_filepath_parser.rb +35 -0
  33. data/lib/parade/parsers/slides_file_content_parser.rb +27 -0
  34. data/lib/parade/renderers/columns_renderer.rb +68 -0
  35. data/lib/parade/renderers/command_line_renderer.rb +142 -0
  36. data/lib/parade/renderers/html_with_pygments.rb +42 -0
  37. data/lib/parade/renderers/inline_images.rb +31 -0
  38. data/lib/parade/renderers/special_paragraph_renderer.rb +23 -0
  39. data/lib/parade/renderers/update_image_paths.rb +75 -0
  40. data/lib/parade/section.rb +183 -0
  41. data/lib/parade/server.rb +139 -0
  42. data/lib/parade/slide.rb +128 -0
  43. data/lib/parade/version.rb +3 -0
  44. data/lib/public/css/960.css +653 -0
  45. data/lib/public/css/fg.menu.css +114 -0
  46. data/lib/public/css/ghf_marked.css +180 -0
  47. data/lib/public/css/jquery-terminal.css +73 -0
  48. data/lib/public/css/onepage.css +62 -0
  49. data/lib/public/css/parade.css +450 -0
  50. data/lib/public/css/pdf.css +13 -0
  51. data/lib/public/css/reset.css +53 -0
  52. data/lib/public/css/spinner_bar.gif +0 -0
  53. data/lib/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
  54. data/lib/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
  55. data/lib/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
  56. data/lib/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
  57. data/lib/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
  58. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
  59. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
  60. data/lib/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
  61. data/lib/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
  62. data/lib/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
  63. data/lib/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
  64. data/lib/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
  65. data/lib/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
  66. data/lib/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
  67. data/lib/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
  68. data/lib/public/css/theme/ui.accordion.css +9 -0
  69. data/lib/public/css/theme/ui.all.css +2 -0
  70. data/lib/public/css/theme/ui.base.css +9 -0
  71. data/lib/public/css/theme/ui.core.css +37 -0
  72. data/lib/public/css/theme/ui.datepicker.css +62 -0
  73. data/lib/public/css/theme/ui.dialog.css +13 -0
  74. data/lib/public/css/theme/ui.progressbar.css +4 -0
  75. data/lib/public/css/theme/ui.resizable.css +13 -0
  76. data/lib/public/css/theme/ui.slider.css +17 -0
  77. data/lib/public/css/theme/ui.tabs.css +9 -0
  78. data/lib/public/css/theme/ui.theme.css +245 -0
  79. data/lib/public/favicon.ico +0 -0
  80. data/lib/public/js/coffee-script.js +8 -0
  81. data/lib/public/js/fg.menu.js +645 -0
  82. data/lib/public/js/jTypeWriter.js +26 -0
  83. data/lib/public/js/jquery-1.4.2.js +6240 -0
  84. data/lib/public/js/jquery-print.js +109 -0
  85. data/lib/public/js/jquery-pubsub.js +27 -0
  86. data/lib/public/js/jquery-terminal.js +2712 -0
  87. data/lib/public/js/jquery.batchImageLoad.js +56 -0
  88. data/lib/public/js/jquery.cycle.all.js +1284 -0
  89. data/lib/public/js/keyboard.js +733 -0
  90. data/lib/public/js/parade-code-execution.js +122 -0
  91. data/lib/public/js/parade-command-input.js +16 -0
  92. data/lib/public/js/parade-command-visor.js +92 -0
  93. data/lib/public/js/parade-keyboard-input.js +54 -0
  94. data/lib/public/js/parade.js +675 -0
  95. data/lib/public/js/spine.js +904 -0
  96. data/lib/templates/config.ru.erb +4 -0
  97. data/lib/templates/showoff.erb +27 -0
  98. data/lib/templates/slides.md.erb +25 -0
  99. data/lib/views/header.erb +73 -0
  100. data/lib/views/index.erb +53 -0
  101. data/lib/views/inline_css.erb +3 -0
  102. data/lib/views/inline_js.erb +3 -0
  103. data/lib/views/onepage.erb +17 -0
  104. data/lib/views/pdf.erb +17 -0
  105. data/lib/views/slide.erb +5 -0
  106. metadata +317 -0
@@ -0,0 +1,122 @@
1
+ window.CodeExecutor = Spine.Class.create({
2
+ init: function() {
3
+ $.subscribe("code:execute",$.proxy(function(e,code) {
4
+ this.executeCode(code);
5
+ },this));
6
+ $.subscribe("code:execute:visible",$.proxy(function(e,code) {
7
+ this.executeVisibleCode();
8
+ },this));
9
+ },
10
+ visibleCodeBlocks: function() {
11
+ return { ruby : $('.execute .sh_ruby pre:visible'),
12
+ js : $('.execute .sh_javascript pre:visible'),
13
+ coffee : $('.execute .sh_coffeescript pre:visible') }
14
+ },
15
+ executeVisibleCode: function() {
16
+
17
+ var codeBlocks = this.visibleCodeBlocks();
18
+ var supportedCodeBlockLanguages = Object.keys(codeBlocks);
19
+
20
+ for (var i = 0; i < supportedCodeBlockLanguages.length; i++) {
21
+ var lang = supportedCodeBlockLanguages[i];
22
+
23
+ if (codeBlocks[lang].length > 0) {
24
+ var code = codeBlocks[lang].text();
25
+ this.executeCode({ lang: lang, code: code });
26
+ }
27
+ }
28
+ },
29
+ executeCode: function(code) {
30
+ var codeExecutor = this.executorForLanguage(code['lang']);
31
+ $.publish('code:execution:started');
32
+ codeExecutor(code['code']);
33
+ },
34
+ executorForLanguage: function(language) {
35
+ return this.supportedLanguages()[language];
36
+ },
37
+ supportedLanguages: function() {
38
+ return { ruby : this.executeRuby,
39
+ js : this.executeJavaScript,
40
+ coffee : this.executeCoffee };
41
+ },
42
+ executeJavaScript: function(code) {
43
+ var result = eval(code);
44
+ setTimeout(function() { $.publish('code:execution:finished'); }, 250 );
45
+ if (result != null) { $.publish('code:execution:results',result); }
46
+ },
47
+ executeRuby: function(code) {
48
+ $.get('/eval_ruby', { code: code }, function(result) {
49
+ if (result != null) { $.publish('code:execution:results',result); }
50
+ $.publish('code:execution:finished');
51
+ });
52
+ },
53
+ executeCoffee: function(code) {
54
+ // When Coffeescript completes it's work the final result is encapsulated
55
+ // within it. To get around it, the result of the last evaluation needs to
56
+ // be assigned to the window, which we can then use for the purposes of
57
+ // displaying the results.
58
+
59
+ var codeWithAssignmentToResults = code + ';window.result=result;'
60
+ eval(CoffeeScript.compile(codeWithAssignmentToResults));
61
+
62
+ setTimeout(function() { $.publish('code:execution:finished'); }, 250 );
63
+ if (result != null) { $.publish('code:execution:results',result); }
64
+ }
65
+ });
66
+
67
+ window.CodeViewer = Spine.Class.create({
68
+ init: function() {
69
+ $.subscribe("code:execution:started",$.proxy(function(e) {
70
+ this.printResults("Executing...");
71
+ },this));
72
+ $.subscribe("code:execution:finished",$.proxy(function(e) {
73
+ // When the execution is finished there is nothing that needs
74
+ // to happen at the moment
75
+ },this));
76
+ $.subscribe("code:execution:results",$.proxy(function(e,result) {
77
+ this.printResults(result);
78
+ },this));
79
+ $.subscribe("code:execution:clear",$.proxy(function(e,result) {
80
+ this.removeResults();
81
+ },this));
82
+
83
+ this.resultsView = $('.results');
84
+ this.resultsView.live('click',function() {
85
+ $(this).hide();
86
+ });
87
+
88
+ },
89
+ toggle: function() {
90
+ },
91
+ printResults: function(result) {
92
+ var formattedResults = $.print(result, {max_string:500});
93
+ this.removeResults();
94
+ this.resultsView.show();
95
+ this.resultsView.html(formattedResults)
96
+ },
97
+ removeResults: function() {
98
+ this.resultsView.html("");
99
+ this.resultsView.hide();
100
+ }
101
+ })
102
+
103
+ $(document).ready(function() {
104
+ codeExecutor = new CodeExecutor;
105
+ codeViewer = new CodeViewer;
106
+
107
+ $('.execute .sh_javascript pre').live("click", function() {
108
+ var code = $(this).text();
109
+ $.publish('code:execute',{ lang: 'js', code: code, elem: $(this) });
110
+ });
111
+
112
+ $('.execute .sh_ruby pre').live("click", function() {
113
+ var code = $(this).text();
114
+ $.publish('code:execute',{ lang: 'ruby', code: code, elem: $(this) });
115
+ });
116
+
117
+ $('.execute .sh_coffeescript pre').live("click", function() {
118
+ var code = $(this).text();
119
+ $.publish('code:execute',{ lang: 'coffee', code: code, elem: $(this) });
120
+ });
121
+
122
+ });
@@ -0,0 +1,16 @@
1
+ $(document).ready(function() {
2
+
3
+ var publishCommand = function(notificationName) {
4
+ return function(tokens) { $.publish(notificationName); };
5
+ }
6
+
7
+ window.TerminalCommands = {
8
+ next : publishCommand('presentation:slide:next'),
9
+ previous : publishCommand('presentation:slide:previous'),
10
+ goto : function(tokens) {
11
+ var slide = parseInt(tokens[0]) - 1;
12
+ $.publish('presentation:slide:location:change',slide);
13
+ }
14
+ };
15
+
16
+ });
@@ -0,0 +1,92 @@
1
+ (function($) {
2
+ $.fn.tilda = function(eval, options) {
3
+ if ($('body').data('tilda')) {
4
+ return $('body').data('tilda').terminal;
5
+ }
6
+ this.addClass('tilda');
7
+ options = options || {};
8
+ eval = eval || function(command, term) {
9
+ term.echo("you don't set eval for tilda");
10
+ };
11
+ var settings = {
12
+ prompt: '$>',
13
+ name: '$',
14
+ height: 50,
15
+ enabled: false,
16
+ greetings: ''
17
+ };
18
+ if (options) {
19
+ $.extend(settings, options);
20
+ }
21
+ this.append('<div class="td"></div>');
22
+ var self = this;
23
+ self.terminal = this.find('.td').terminal(eval, settings);
24
+ var focus = false;
25
+ $(document.documentElement).keypress(function(e) {
26
+ if (e.which == 96) {
27
+ self.slideToggle('fast');
28
+ self.terminal.set_command('');
29
+ self.terminal.focus(focus = !focus);
30
+
31
+ if (focus) {
32
+ $.publish("console:show");
33
+ } else {
34
+ $.publish("console:hidden");
35
+ }
36
+
37
+ self.terminal.attr({
38
+ scrollTop: self.terminal.attr("scrollHeight")
39
+ });
40
+ }
41
+ });
42
+ $('body').data('tilda', this);
43
+ this.hide();
44
+ return self;
45
+ };
46
+ })(jQuery);
47
+
48
+
49
+ $(document).ready(function() {
50
+
51
+ var TerminalCommandMapper = {
52
+ find: function(input,terminal) {
53
+ var definedCommands = Object.keys(this.commands);
54
+ var regexInput = new RegExp(input);
55
+ var matchedCommands = [];
56
+
57
+ for (var i = 0; i < definedCommands.length; i++) {
58
+ var currentCommand = definedCommands[i];
59
+ if (regexInput.exec(currentCommand)) {
60
+ matchedCommands.push(currentCommand);
61
+ }
62
+ }
63
+
64
+ var unknownCommand = function() { terminal.echo('Unknown Command: ' + input); };
65
+ var MultipleMatchCommand = function() { terminal.echo('Multiple commands matched: `' + input + '` - ' + matchedCommands); };
66
+
67
+ var finalMatchedCommand = unknownCommand;
68
+
69
+ if (matchedCommands.length == 1) {
70
+ finalMatchedCommand = this.commands[ matchedCommands[0] ];
71
+ } else if (matchedCommands.length > 1) {
72
+ finalMatchedCommand = MultipleMatchCommand
73
+ }
74
+
75
+ return finalMatchedCommand;
76
+ },
77
+ commands: TerminalCommands
78
+ }
79
+
80
+ $('#tilda').tilda(function(command, terminal) {
81
+ if (command.length == 0) { return; }
82
+
83
+ var tokens = command.split(' ');
84
+ var name = tokens[0];
85
+ var params = tokens.slice(1,tokens.length);
86
+
87
+ var commandMatchingName = TerminalCommandMapper.find(name,terminal);
88
+ commandMatchingName(params);
89
+ });
90
+
91
+
92
+ });
@@ -0,0 +1,54 @@
1
+ //
2
+ // Register all the keyboard inputs for Parade presentation events.
3
+ //
4
+
5
+ $(document).ready(function() {
6
+
7
+ $.subscribe("console:show",function() {
8
+ KeyboardJS.disable();
9
+ });
10
+
11
+ $.subscribe("console:hidden",function() {
12
+ KeyboardJS.enable();
13
+ });
14
+
15
+ KeyboardJS.on('space, right, pagedown, down', function(){
16
+ $.publish("presentation:slide:next");
17
+ });
18
+
19
+ KeyboardJS.on('shift + space, left, pageup, up', function(){
20
+ $.publish("presentation:slide:previous");
21
+ });
22
+
23
+ KeyboardJS.on('h, ?', function(){
24
+ $.publish("help:toggle");
25
+ });
26
+
27
+ KeyboardJS.on('b, f', function(){
28
+ $.publish("presentation:footer:toggle");
29
+ });
30
+
31
+ KeyboardJS.on('d', function(){
32
+ $.publish("debug:toggle");
33
+ });
34
+
35
+ KeyboardJS.on('n', function(){
36
+ $.publish("presentation:speaker:notes:toggle");
37
+ });
38
+
39
+ KeyboardJS.on('shift + p', function(){
40
+ $.publish("presentation:pause:toggle");
41
+ });
42
+
43
+ KeyboardJS.on('p', function(){
44
+ $.publish("presentation:preshow:toggle");
45
+ });
46
+
47
+ KeyboardJS.on('enter', function(){
48
+ $.publish("code:execute:visible")
49
+ });
50
+
51
+ KeyboardJS.on('escape', function(){
52
+ $.publish("code:execution:clear");
53
+ });
54
+ });
@@ -0,0 +1,675 @@
1
+ function ListMenu(s) {
2
+ this.slide = s
3
+ this.typeName = 'ListMenu'
4
+ this.itemLength = 0;
5
+ this.items = new Array();
6
+ this.addItem = function (key, text, slide) {
7
+ if (key.length > 1) {
8
+ thisKey = key.shift()
9
+ if (!this.items[thisKey]) {
10
+ this.items[thisKey] = new ListMenu(slide)
11
+ }
12
+ this.items[thisKey].addItem(key, text, slide)
13
+ } else {
14
+ thisKey = key.shift()
15
+ this.items[thisKey] = new ListMenuItem(text, slide)
16
+ }
17
+ }
18
+ this.getList = function() {
19
+ var newMenu = $("<ul>")
20
+ for(var i in this.items) {
21
+ var item = this.items[i]
22
+ var domItem = $("<li>")
23
+ if (item.typeName == 'ListMenu') {
24
+ choice = $("<a rel=\"" + (item.slide - 1) + "\" href=\"#\">" + i + "</a>")
25
+ domItem.append(choice)
26
+ domItem.append(item.getList())
27
+ }
28
+ if (item.typeName == 'ListMenuItem') {
29
+ choice = $("<a rel=\"" + (item.slide - 1) + "\" href=\"#\">" + item.slide + '. ' + item.textName + "</a>")
30
+ domItem.append(choice)
31
+ }
32
+ newMenu.append(domItem)
33
+ }
34
+ return newMenu
35
+ }
36
+ }
37
+
38
+ function ListMenuItem(t, s) {
39
+ this.typeName = "ListMenuItem"
40
+ this.slide = s
41
+ this.textName = t
42
+ }
43
+
44
+
45
+ $(document).ready(function() {
46
+
47
+ window.Preshow = Spine.Class.create({
48
+ init: function() {
49
+ this.element = $(arguments[0]);
50
+ this.secondsToRun = parseFloat(arguments[1] * 60);
51
+
52
+ $.subscribe("presentation:preshow:toggle",$.proxy(function() {
53
+ this.toggle();
54
+ },this));
55
+
56
+ },
57
+ preshowRunning: false,
58
+ start: function() {
59
+
60
+ if (this.preshowIntervalReference) {
61
+ return;
62
+ }
63
+
64
+ this.preservePresentationSpace();
65
+
66
+ this.load();
67
+
68
+ this.images = this.element.children("img");
69
+
70
+ this.currentImageIndex = 0;
71
+ this.totalImages = this.images.size();
72
+
73
+
74
+ this.preshowRunning = true;
75
+
76
+ $.publish("presentation:preshow:start");
77
+
78
+ this.currentRunTime = 0;
79
+ this.currentRemainingTime = this.secondsToRun;
80
+
81
+ this.nextImage();
82
+ this.preshowIntervalReference = setInterval($.proxy(this.perform,this),1000);
83
+
84
+ },
85
+ preservePresentationSpace: function() {
86
+ this.storedPresentationSpace = this.element.html();
87
+ },
88
+ restorePresentationSpace: function() {
89
+ this.element.empty();
90
+ this.element.html(this.storedPresentationSpace);
91
+ },
92
+ displayImagesInterval: 5,
93
+ perform: function() {
94
+ this.currentRunTime ++;
95
+ this.currentRemainingTime --;
96
+
97
+ time = this.secondsToTime(this.currentRemainingTime);
98
+
99
+ $('#preshow_timer').text(time + ' to go-time')
100
+ var description = this.preshowDescription && this.preshowDescription[tmpImg.attr("ref")]
101
+
102
+ if(description) {
103
+ $('#tips').show();
104
+ $('#tips').text(description);
105
+ } else {
106
+ $('#tips').hide();
107
+ }
108
+
109
+ if ((this.currentRunTime % this.displayImagesInterval) == 0) {
110
+ this.nextImage();
111
+ }
112
+
113
+ this.preshowTip();
114
+
115
+ if (this.currentRemainingTime <= 0) {
116
+ this.stop();
117
+ }
118
+
119
+ },
120
+ stop: function() {
121
+
122
+ if (!this.preshowIntervalReference) {
123
+ return;
124
+ }
125
+
126
+ this.preshowRunning = false;
127
+ window.clearInterval(this.preshowIntervalReference);
128
+ this.preshowIntervalReference = undefined;
129
+
130
+ $('#preshow').remove();
131
+ $('#tips').remove();
132
+ $('#preshow_timer').remove();
133
+
134
+ this.restorePresentationSpace();
135
+
136
+ $.publish("presentation:preshow:stop");
137
+
138
+ },
139
+ toggle: function() {
140
+
141
+ if (this.preshowIntervalReference) {
142
+ this.stop();
143
+ } else {
144
+ this.start();
145
+ }
146
+
147
+ },
148
+ preshowPath: "preshow",
149
+ load: function() {
150
+
151
+ $.getJSON(this.preshowPath, false, $.proxy(function(data) {
152
+
153
+ this.element.after("<div id='preshow'></div><div id='tips'></div><div id='preshow_timer'></div>")
154
+
155
+ $.each(data, $.proxy(function(i, n) {
156
+ if(n == "preshow.json") {
157
+ // has a descriptions file
158
+ $.getJSON("/file/preshow/preshow.json", false, function(data) {
159
+ this.preshowDescription = data;
160
+ })
161
+ } else {
162
+ $('#preshow').append('<img ref="' + n + '" src="/file/preshow/' + n + '"/>');
163
+ this.images = $("#preshow > img");
164
+ this.totalImages = this.images.size();
165
+ }
166
+ },this));
167
+
168
+ },this));
169
+
170
+ },
171
+ nextImage: function() {
172
+ this.currentImageIndex ++;
173
+ if((this.currentImageIndex + 1) > this.totalImages) {
174
+ this.currentImageIndex = 0;
175
+ }
176
+
177
+ this.element.empty();
178
+ tmpImg = this.images.eq(this.currentImageIndex).clone();
179
+ $(tmpImg).attr('width', '1020');
180
+ this.element.html(tmpImg);
181
+ },
182
+ preshowTip: function() {
183
+
184
+ },
185
+ secondsToTime: function(seconds) {
186
+ minutes = Math.floor(seconds / 60)
187
+ seconds = seconds - (minutes * 60)
188
+ if(seconds < 10) {
189
+ seconds = "0" + seconds
190
+ }
191
+ return minutes + ":" + seconds
192
+ }
193
+ });
194
+
195
+ window.ToggleView = Spine.Class.create({
196
+ init: function () {
197
+
198
+ this.element = $(arguments[0])
199
+
200
+ var eventPrefix = arguments[1]
201
+
202
+ $.subscribe( eventPrefix + ":show",$.proxy(function() {
203
+ this.show()
204
+ },this));
205
+
206
+ $.subscribe( eventPrefix + ":hide",$.proxy(function() {
207
+ this.hide()
208
+ },this));
209
+
210
+ $.subscribe( eventPrefix + ":toggle",$.proxy(function() {
211
+ this.toggle()
212
+ },this));
213
+
214
+ },
215
+ show: function() {
216
+ this.element.show()
217
+ },
218
+ hide: function() {
219
+ this.element.hide()
220
+ },
221
+ toggle: function() {
222
+ this.element.toggle()
223
+ }
224
+ });
225
+
226
+ window.Footer = ToggleView.sub({
227
+ init: function() {
228
+ this.constructor.__super__.init.apply(this, arguments);
229
+
230
+ this.progressView = $("#slideInfo")
231
+ $.subscribe("presentation:slide:didChange",$.proxy(this.updateProgress,this));
232
+ },
233
+ progressPercentage: function (slideIndex,slideCount) {
234
+ return Math.ceil(((slideIndex + 1) / slideCount) * 100)
235
+ },
236
+ updateProgress: function(event,slideIndex,slideCount) {
237
+ percent = this.progressPercentage(slideIndex,slideCount);
238
+ this.progressView.text((slideIndex + 1) + '/' + slideCount + ' - ' + percent + '%')
239
+ }
240
+ });
241
+
242
+ window.HelpMenu = ToggleView.sub();
243
+
244
+ window.PauseScreen = ToggleView.sub();
245
+
246
+ window.SpeakerNotes = ToggleView.sub({
247
+ init: function() {
248
+ this.constructor.__super__.init.apply(this, arguments)
249
+
250
+ $.subscribe("presentation:slide:didChange",$.proxy(this.updateNotes,this));
251
+ },
252
+ updateNotes: function(event,slide) {
253
+ // Update the text from the slide's notes
254
+ }
255
+ });
256
+
257
+ window.DebugView = ToggleView.sub({
258
+ log: function(text) {
259
+ this.element.text(text);
260
+ }
261
+ });
262
+
263
+
264
+ window.Slide = Spine.Class.create({
265
+ index: 0,
266
+ maxSlides: 0,
267
+ init: function() {
268
+ this.htmlContent = arguments[0];
269
+ this.index = arguments[1];
270
+ this.maxSlides = arguments[2];
271
+
272
+ this.transition = this.htmlContent.attr('data-transition');
273
+
274
+ this.increments = this.htmlContent.find(".incremental > ul > li");
275
+ this.currentIncrement = 0;
276
+
277
+ if (this.increments.size() == 0) {
278
+ this.increments = this.htmlContent.find(".incremental pre pre")
279
+ this.codeIncremental = true;
280
+ }
281
+
282
+ this.increments.each(function(index, increment) {
283
+ $(increment).css('visibility', 'hidden');
284
+ });
285
+
286
+ },
287
+ currentIncrement: 0,
288
+ increment: function(incrementIndex) {
289
+ var increment = this.increments.eq(incrementIndex);
290
+
291
+ if (this.codeIncremental && increment.hasClass('command')) {
292
+ increment.css('visibility', 'visible').jTypeWriter({duration:1.0});
293
+ } else {
294
+ increment.css('visibility', 'visible');
295
+ }
296
+
297
+ },
298
+ nextIncrement: function() {
299
+ this.increment(this.currentIncrement);
300
+ this.trigger("parade:incr");
301
+ this.currentIncrement ++;
302
+ },
303
+ hasIncrement: function() {
304
+ return (this.currentIncrement < this.increments.size());
305
+ },
306
+ showAllIncrements: function() {
307
+ this.increments.each(function(index, increment) {
308
+ $(increment).css('visibility', 'visible');
309
+ });
310
+ this.currentIncrement = this.increments.size();
311
+ },
312
+ isFullPage: function() {
313
+ return this.htmlContent.find(".content").is('.full-page');
314
+ },
315
+ notes: function() {
316
+ return this.htmlContent.find("p.notes").text();
317
+ },
318
+ goFullPage: function() {
319
+ this.htmlContent.css({'width' : '100%', 'text-align' : 'center', 'overflow' : 'visible'});
320
+ },
321
+ trigger: function(eventName) {
322
+ var event = jQuery.Event(eventName);
323
+ this.htmlContent.find(".content").trigger(event,this);
324
+ return event;
325
+ }
326
+ });
327
+
328
+ window.Slides = Spine.Class.create({
329
+ init: function() {
330
+ this.element = $("#slides");
331
+ this.slides = $("#slides > .slide");
332
+ },
333
+ show: function() {
334
+ this.element.show()
335
+ },
336
+ hide: function() {
337
+ this.element.hide()
338
+ },
339
+ load: function() {
340
+
341
+ // $("#slides img").batchImageLoad({
342
+ // loadingCompleteCallback: presentation.initialize()
343
+ // });
344
+
345
+ // $("#slides").load("/slides",function() {
346
+ // console.log("loading slides complete");
347
+ // $("#slides img").batchImageLoad({
348
+ // loadingCompleteCallback: presentation.initialize()
349
+ // });
350
+ // });
351
+ },
352
+ size: function() {
353
+ return this.slides.size();
354
+ },
355
+ at: function(index) {
356
+ return new Slide($(this.slides.eq(index)),index,this.size());
357
+ }
358
+ });
359
+
360
+ window.NavigationMenu = ToggleView.sub({
361
+ init: function() {
362
+ this.constructor.__super__.init.apply(this,arguments);
363
+ this.menuView = $("#navigation");
364
+ },
365
+ populate: function(slides) {
366
+
367
+ var menu = new ListMenu()
368
+
369
+ slides.each(function(slideCount, slideElement) {
370
+
371
+ // TODO: by default the menu is populated with the html,
372
+ // allow the user to specify some metadata
373
+
374
+ content = $(slideElement).children(".content")
375
+ shortTitle = $(content).text().substr(0, 20)
376
+ path = $(content).attr('ref').split('/')
377
+
378
+ menu.addItem(path, shortTitle, slideCount + 1)
379
+ })
380
+
381
+ this.menuView.html(menu.getList());
382
+
383
+ this.element.menu({
384
+ content: this.menuView.html(),
385
+ flyOut: true,
386
+ width: 200
387
+ });
388
+
389
+ },
390
+ toggle: function() {
391
+ this.constructor.__super__.toggle.apply(this,arguments);
392
+ this.open();
393
+ },
394
+ show: function() {
395
+ this.constructor.__super__.show.apply(this,arguments);
396
+ this.open();
397
+ },
398
+ open: function() {
399
+ this.element.trigger('click');
400
+ }
401
+ });
402
+
403
+
404
+ window.Presentation = Spine.Class.create({
405
+ slides: new Slides(),
406
+ slidenum: 0,
407
+ presentationFrame: $("#preso"),
408
+
409
+ footer: new Footer("#footer","presentation:footer"),
410
+ helpMenu: new HelpMenu("#help","help"),
411
+ pauseScreen: new PauseScreen("#pauseScreen","presentation:pause"),
412
+ speakerNotes: new SpeakerNotes("#notesInfo","presentation:speaker:notes"),
413
+ debugView: new DebugView("#debugInfo","debug"),
414
+ navigationMenu: new NavigationMenu("#navmenu","presentation:navigation"),
415
+
416
+ init: function() {
417
+
418
+ },
419
+ start: function() {
420
+ console.log("Initializing Presentation");
421
+
422
+ this.slides.show();
423
+
424
+ // TODO: Another entity to center the slides should be put in place
425
+ this.centerSlides();
426
+
427
+ // Copy the slides into the presentation area
428
+ this.presentationFrame.empty();
429
+ this.slides.slides.appendTo(this.presentationFrame);
430
+
431
+ // Create the jquery cycle in the presentation frame
432
+ this.presentationFrame.cycle({
433
+ timeout: 0
434
+ });
435
+
436
+ this.navigationMenu.hide();
437
+ this.navigationMenu.populate(this.slides.slides);
438
+
439
+ $.subscribe("presentation:slide:location:change",$.proxy(function(event,slideIndex) {
440
+ this.gotoSlide(slideIndex);
441
+ },this));
442
+
443
+ this.showFirstSlide();
444
+
445
+ this.presentationFrame.trigger("parade:loaded");
446
+
447
+ $.subscribe("presentation:slide:next",$.proxy(function() {
448
+ this.nextStep();
449
+ },this));
450
+
451
+ $.subscribe("presentation:slide:previous",$.proxy(function() {
452
+ this.prevStep();
453
+ },this));
454
+
455
+ $.subscribe("presentation:reload",$.proxy(function() {
456
+ // this.loadSlides(loadSlidesBool, loadSlidesPrefix)
457
+ this.loadSlides()
458
+
459
+ // FIXME: currently the reload is making the slides appear lower
460
+ // then where they are originally.
461
+ this.slidenum = 0
462
+ this.showSlide()
463
+ },this));
464
+
465
+ $.subscribe("presentation:preshow:start",$.proxy(function() {
466
+ this.footer.hide();
467
+ },this));
468
+
469
+ $.subscribe("presentation:preshow:stop",$.proxy(function() {
470
+ this.footer.show();
471
+
472
+ // Returning from a presentation requires the presentation frame to
473
+ // be rebuilt.
474
+
475
+ this.presentationFrame.cycle({
476
+ timeout: 0
477
+ });
478
+ this.showSlide();
479
+
480
+ },this));
481
+
482
+ },
483
+ centerSlides: function() {
484
+ console.log("Centering Slides");
485
+ var presentation = this;
486
+ this.slides.slides.each(function(s,slide) {
487
+ presentation.centerSlide(slide);
488
+ });
489
+ },
490
+ centerSlide: function(slide) {
491
+ var slideObject = $(slide);
492
+ var slide_content = slideObject.children(".content").first();
493
+ var height = slide_content.height();
494
+ var margin_top = (0.5 * parseFloat(slideObject.height())) - (0.5 * parseFloat(height));
495
+ if (margin_top < 0) {
496
+ margin_top = 0;
497
+ }
498
+ slide_content.css('margin-top', margin_top);
499
+ },
500
+ showFirstSlide: function() {
501
+ this.slidenum = WindowToSlideLocation.location();
502
+ this.updateSlide();
503
+ this.showSlide()
504
+ },
505
+ gotoSlide: function(slideNum) {
506
+ this.slidenum = parseInt(slideNum)
507
+ if (!isNaN(this.slidenum)) {
508
+ this.showSlide()
509
+ }
510
+ },
511
+ slideTotal: function() {
512
+ return this.slides.size();
513
+ },
514
+ nextSlide: function() {
515
+ this.slidenum ++;
516
+ this.updateSlide();
517
+ this.showSlide();
518
+ },
519
+ previousSlide: function() {
520
+ this.slidenum --;
521
+ this.updateSlide();
522
+ this.currentSlide.transition = "none";
523
+ this.currentSlide.showAllIncrements();
524
+ this.showSlide();
525
+ },
526
+ updateSlide: function() {
527
+ this.currentSlide = this.slides.at(this.slidenum);
528
+ },
529
+ showSlide: function() {
530
+
531
+ if(this.slidenum < 0) {
532
+ this.slidenum = 0
533
+ return
534
+ }
535
+
536
+ var maxSlides = this.slideTotal();
537
+
538
+ if(this.slidenum > (maxSlides - 1)) {
539
+ this.slidenum = maxSlides - 1
540
+ return
541
+ }
542
+
543
+ var currentSlide = this.currentSlide;
544
+
545
+ var transition = currentSlide.transition;
546
+ var slideIsFullPage = currentSlide.isFullPage();
547
+
548
+ if (slideIsFullPage) {
549
+ transition = 'none';
550
+ }
551
+
552
+ $.publish("presentation:slide:willChange",[ this.slidenum, maxSlides ]);
553
+ this.presentationFrame.cycle(this.slidenum, transition);
554
+ $.publish("presentation:slide:didChange",[ this.slidenum, maxSlides ]);
555
+
556
+ if (slideIsFullPage) {
557
+ this.presentationFrame.css({'width' : '100%', 'overflow' : 'visible'});
558
+ currentSlide.goFullPage();
559
+ } else {
560
+ this.presentationFrame.css({'width' : '', 'overflow' : ''});
561
+ }
562
+
563
+ WindowToSlideLocation.updateLocation(this.slidenum + 1);
564
+
565
+ $.publish('code:execution:clear');
566
+
567
+ currentSlide.trigger("parade:show");
568
+
569
+ return currentSlide.notes();
570
+ },
571
+ nextStep: function() {
572
+
573
+ var triggeredEvent = this.currentSlide.trigger("parade:next");
574
+
575
+ if (triggeredEvent.isDefaultPrevented()) {
576
+ return;
577
+ }
578
+
579
+ if (this.currentSlide.hasIncrement()) {
580
+ this.currentSlide.nextIncrement();
581
+ } else {
582
+ this.nextSlide();
583
+ }
584
+ },
585
+ prevStep: function() {
586
+
587
+ var triggeredEvent = this.currentSlide.trigger("parade:prev");
588
+
589
+ if (triggeredEvent.isDefaultPrevented()) {
590
+ return;
591
+ }
592
+
593
+ this.previousSlide();
594
+ },
595
+ debug: function(text) {
596
+ this.debugView.log(text);
597
+ }
598
+ });
599
+
600
+ window.WindowToSlideLocation = Spine.Class.sub();
601
+ WindowToSlideLocation.location = function() {
602
+ var result;
603
+ if (result = window.location.hash.match(/#([0-9]+)/)) {
604
+ return result[result.length - 1] - 1;
605
+ } else {
606
+ return 0;
607
+ }
608
+ }
609
+ WindowToSlideLocation.updateLocation = function(newLocation) {
610
+ window.location.hash = newLocation;
611
+ }
612
+
613
+ window.LocationWatcher = Spine.Class.create({
614
+ init: function() {
615
+ var presentation = this;
616
+ this.watchEnabled = false;
617
+ this.lastResult = this.windowLocation();
618
+
619
+ $.subscribe("presentation:slide:didChange",$.proxy(function(event,slideCount,maxSlides) {
620
+ this.lastResult = slideCount;
621
+ },this));
622
+
623
+ },
624
+ start: function() {
625
+ if (this.watchEnabled === false) {
626
+ this.watchEnabled = true;
627
+ this.perform();
628
+ }
629
+ },
630
+ stop: function() {
631
+ this.watchEnabled = false;
632
+ },
633
+ perform: function() {
634
+ var currentResult = this.windowLocation();
635
+ if (this.lastResult != currentResult) {
636
+ $.publish("presentation:slide:location:change",currentResult);
637
+ }
638
+
639
+ this.lastResult = currentResult;
640
+
641
+ if (this.watchEnabled) {
642
+ setTimeout($.proxy(this.perform,this), 200);
643
+ }
644
+ },
645
+ windowLocation: function() {
646
+ return WindowToSlideLocation.location();
647
+ }
648
+ });
649
+
650
+
651
+ });
652
+
653
+ $(document).ready(function() {
654
+ presentation = new Presentation;
655
+ presentation.start();
656
+
657
+ var locationWatcher = new LocationWatcher();
658
+ locationWatcher.start();
659
+
660
+ preshow = new Preshow("#preso",0.25);
661
+
662
+ // bind event handlers
663
+ /* window.onresize = resized; */
664
+ /* window.onscroll = scrolled; */
665
+ /* window.onunload = unloaded; */
666
+
667
+ $('buttonNav.prev').click(function(){
668
+ $.publish("presentation:slide:previous");
669
+ });
670
+
671
+ $('buttonNav.next').click(function(){
672
+ $.publish("presentation:slide:next");
673
+ });
674
+
675
+ });