parade 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.md +542 -0
- data/Rakefile +15 -0
- data/bin/parade +138 -0
- data/lib/parade.rb +43 -0
- data/lib/parade/commands/commands.rb +84 -0
- data/lib/parade/commands/generate_outline.rb +34 -0
- data/lib/parade/commands/generate_presentation.rb +34 -0
- data/lib/parade/commands/generate_rackup.rb +32 -0
- data/lib/parade/commands/html_output.rb +47 -0
- data/lib/parade/commands/render_from_template.rb +50 -0
- data/lib/parade/commands/static_html.rb +38 -0
- data/lib/parade/commands/static_pdf.rb +39 -0
- data/lib/parade/commands/unknown.rb +23 -0
- data/lib/parade/features/live_ruby.rb +18 -0
- data/lib/parade/features/pdf_presentation.rb +24 -0
- data/lib/parade/features/preshow.rb +11 -0
- data/lib/parade/helpers/encode_image.rb +24 -0
- data/lib/parade/helpers/template_generator.rb +130 -0
- data/lib/parade/metadata.rb +73 -0
- data/lib/parade/metadata/assignment.rb +38 -0
- data/lib/parade/metadata/css_classes.rb +22 -0
- data/lib/parade/metadata/html_id.rb +35 -0
- data/lib/parade/metadata/template.rb +31 -0
- data/lib/parade/parsers/dsl.rb +138 -0
- data/lib/parade/parsers/dsl_file_parser.rb +17 -0
- data/lib/parade/parsers/json_file_parser.rb +67 -0
- data/lib/parade/parsers/markdown_image_paths.rb +44 -0
- data/lib/parade/parsers/markdown_slide_splitter.rb +63 -0
- data/lib/parade/parsers/presentation_directory_parser.rb +36 -0
- data/lib/parade/parsers/presentation_file_parser.rb +27 -0
- data/lib/parade/parsers/presentation_filepath_parser.rb +35 -0
- data/lib/parade/parsers/slides_file_content_parser.rb +27 -0
- data/lib/parade/renderers/columns_renderer.rb +68 -0
- data/lib/parade/renderers/command_line_renderer.rb +142 -0
- data/lib/parade/renderers/html_with_pygments.rb +42 -0
- data/lib/parade/renderers/inline_images.rb +31 -0
- data/lib/parade/renderers/special_paragraph_renderer.rb +23 -0
- data/lib/parade/renderers/update_image_paths.rb +75 -0
- data/lib/parade/section.rb +183 -0
- data/lib/parade/server.rb +139 -0
- data/lib/parade/slide.rb +128 -0
- data/lib/parade/version.rb +3 -0
- data/lib/public/css/960.css +653 -0
- data/lib/public/css/fg.menu.css +114 -0
- data/lib/public/css/ghf_marked.css +180 -0
- data/lib/public/css/jquery-terminal.css +73 -0
- data/lib/public/css/onepage.css +62 -0
- data/lib/public/css/parade.css +450 -0
- data/lib/public/css/pdf.css +13 -0
- data/lib/public/css/reset.css +53 -0
- data/lib/public/css/spinner_bar.gif +0 -0
- data/lib/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
- data/lib/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
- data/lib/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/public/css/theme/ui.accordion.css +9 -0
- data/lib/public/css/theme/ui.all.css +2 -0
- data/lib/public/css/theme/ui.base.css +9 -0
- data/lib/public/css/theme/ui.core.css +37 -0
- data/lib/public/css/theme/ui.datepicker.css +62 -0
- data/lib/public/css/theme/ui.dialog.css +13 -0
- data/lib/public/css/theme/ui.progressbar.css +4 -0
- data/lib/public/css/theme/ui.resizable.css +13 -0
- data/lib/public/css/theme/ui.slider.css +17 -0
- data/lib/public/css/theme/ui.tabs.css +9 -0
- data/lib/public/css/theme/ui.theme.css +245 -0
- data/lib/public/favicon.ico +0 -0
- data/lib/public/js/coffee-script.js +8 -0
- data/lib/public/js/fg.menu.js +645 -0
- data/lib/public/js/jTypeWriter.js +26 -0
- data/lib/public/js/jquery-1.4.2.js +6240 -0
- data/lib/public/js/jquery-print.js +109 -0
- data/lib/public/js/jquery-pubsub.js +27 -0
- data/lib/public/js/jquery-terminal.js +2712 -0
- data/lib/public/js/jquery.batchImageLoad.js +56 -0
- data/lib/public/js/jquery.cycle.all.js +1284 -0
- data/lib/public/js/keyboard.js +733 -0
- data/lib/public/js/parade-code-execution.js +122 -0
- data/lib/public/js/parade-command-input.js +16 -0
- data/lib/public/js/parade-command-visor.js +92 -0
- data/lib/public/js/parade-keyboard-input.js +54 -0
- data/lib/public/js/parade.js +675 -0
- data/lib/public/js/spine.js +904 -0
- data/lib/templates/config.ru.erb +4 -0
- data/lib/templates/showoff.erb +27 -0
- data/lib/templates/slides.md.erb +25 -0
- data/lib/views/header.erb +73 -0
- data/lib/views/index.erb +53 -0
- data/lib/views/inline_css.erb +3 -0
- data/lib/views/inline_js.erb +3 -0
- data/lib/views/onepage.erb +17 -0
- data/lib/views/pdf.erb +17 -0
- data/lib/views/slide.erb +5 -0
- 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
|
+
});
|