parade 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,35 @@
1
+ require_relative 'presentation_directory_parser'
2
+ require_relative 'presentation_file_parser'
3
+ require_relative 'slides_file_content_parser'
4
+
5
+ module Parade
6
+ module Parsers
7
+
8
+ class PresentationFilepathParser
9
+
10
+ def self.parse(filepath,options = {})
11
+ return nil unless File.exists? filepath
12
+
13
+ if File.directory? filepath
14
+ PresentationDirectoryParser.parse filepath, options
15
+ else
16
+
17
+ if presentation_file?(filepath)
18
+ PresentationFileParser.parse filepath, options
19
+ else
20
+ SlidesFileContentParser.parse filepath, options
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+
28
+ def self.presentation_file?(filepath)
29
+ File.basename(filepath) == "parade"
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'markdown_image_paths'
2
+ require_relative 'markdown_slide_splitter'
3
+
4
+ module Parade
5
+ module Parsers
6
+
7
+ module SlidesFileContentParser
8
+ def self.parse(filepath,options = {})
9
+ slides_content = File.read(filepath)
10
+ relative_path = File.dirname(filepath).gsub(options[:root_path].gsub(/\/$/,''),'')
11
+ slides_content = MarkdownImagePaths.parse(slides_content,:path => relative_path)
12
+
13
+ create_section_with slides_content
14
+ end
15
+
16
+ private
17
+
18
+ def self.create_section_with(slides_content)
19
+ section = Section.new
20
+ section.add_slides(MarkdownSlideSplitter.parse(slides_content))
21
+ section
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,68 @@
1
+ module Parade
2
+ module Renderers
3
+
4
+ #
5
+ # With the given HTML content, search for the CSS class for the HTML element
6
+ # and when found generate columns for each element found. The size of the
7
+ # columns is a division of the number of segments.
8
+ #
9
+ class ColumnsRenderer
10
+
11
+ attr_accessor :css_class
12
+ attr_accessor :html_element
13
+ attr_accessor :segments
14
+
15
+ #
16
+ # @example Creating a ColumnsRenderer
17
+ #
18
+ # Creation of a column renderer that will look for slides with the class
19
+ # 'columns', and create columns out of all h2 elements found, dividing
20
+ # them across 12 elements.
21
+ #
22
+ # ColumnsRenderer.new(:css_class => 'columns',:html_element => "h2",:segments => 12)
23
+ #
24
+ def initialize(params={})
25
+ params.each {|k,v| send("#{k}=",v) if respond_to? "#{k}=" }
26
+ end
27
+
28
+ def render(content)
29
+
30
+ html = Nokogiri::XML.fragment(content)
31
+ parser = CommandlineParser.new
32
+
33
+ html.css(".#{css_class}").each do |slide|
34
+
35
+ columns = []
36
+ slop = []
37
+
38
+ chunks = slide.children.chunk {|child| child.name == html_element }
39
+
40
+ slide.children = ""
41
+
42
+ slide['class'] += " container_#{segments}"
43
+ current_column = slide
44
+
45
+ column_count = chunks.find_all {|is_column,contents| is_column }.count
46
+
47
+ chunks.each do |is_column,contents|
48
+
49
+ if is_column
50
+ slide.add_child current_column unless current_column == slide
51
+ current_column = Nokogiri::XML::Node.new('div',html)
52
+ current_column['class'] = "grid_#{ segments / column_count }"
53
+ end
54
+
55
+ contents.each {|content| current_column.add_child content }
56
+ end
57
+
58
+ slide.add_child current_column
59
+
60
+ end
61
+
62
+ html.to_s
63
+
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,142 @@
1
+ require 'parslet'
2
+
3
+ module Parade
4
+ module Renderers
5
+
6
+ #
7
+ # Slides that have been marked as 'commandline' will be processed here to
8
+ # ensure that the command portion is played out as if typed. Followed by
9
+ # the result which appears after the command is completed.
10
+ #
11
+ # @example Slide marker to denote a command-line slide
12
+ #
13
+ # !SLIDE commandline incremental
14
+ #
15
+ #
16
+ # To denote the command, it needs to be prefaced with a `$`. The remaining
17
+ # code is considered to be the result.
18
+ #
19
+ # @example Contents of a slide to show a command and a result
20
+ #
21
+ # ```bash
22
+ # $ git commit -am 'incremental bullet points working'
23
+ # [master ac5fd8a] incremental bullet points working
24
+ # 2 files changed, 32 insertions(+), 5 deletions(-)
25
+ # ```
26
+ #
27
+ class CommandLineRenderer
28
+
29
+ #
30
+ # @param [String] html_content the html content of a single slide that
31
+ # will have the commandline rendered correctly if it is a class on
32
+ # the slide.
33
+ # @return [String] the same html content if there is no commandline class
34
+ # or the new rendered html content with the new required HTML elements.
35
+ #
36
+ def self.render(html_content)
37
+
38
+ html = Nokogiri::XML.fragment(html_content)
39
+ parser = CommandlineParser.new
40
+
41
+ html.css('.commandline pre').each do |code|
42
+ out = code.text
43
+ code.content = ''
44
+ tree = parser.parse(out)
45
+ transform = Parslet::Transform.new do
46
+ rule(:prompt => simple(:prompt), :input => simple(:input), :output => simple(:output)) do
47
+ command = Nokogiri::XML::Node.new('pre', html)
48
+ command.set_attribute('class', 'command')
49
+ command.content = "#{prompt} #{input}"
50
+ code << command
51
+
52
+ # Add newline after the input so that users can
53
+ # advance faster than the typewriter effect
54
+ # and still keep inputs on separate lines.
55
+ code << "\n"
56
+
57
+ unless output.to_s.empty?
58
+ result = Nokogiri::XML::Node.new('pre', html)
59
+ result.set_attribute('class', 'result')
60
+ result.content = output
61
+ code << result
62
+ end
63
+
64
+ end
65
+ end
66
+ transform.apply(tree)
67
+ end
68
+
69
+ html.to_s
70
+
71
+ end
72
+
73
+ end
74
+
75
+ # For parsing commandline slide content.
76
+ class CommandlineParser < Parslet::Parser
77
+
78
+ rule(:prompt) do
79
+ str('$') | str('#') | str('>>')
80
+ end
81
+
82
+ rule(:text) do
83
+ match['[:print:]'].repeat
84
+ end
85
+
86
+ rule(:singleline_input) do
87
+ (str("\\\n").absent? >> match['[:print:]']).repeat
88
+ end
89
+
90
+ rule(:input) do
91
+ multiline_input | singleline_input
92
+ end
93
+
94
+ rule(:multiline_input) do
95
+
96
+ # some command \
97
+ # continued \
98
+ # \
99
+ # and stop
100
+ ( singleline_input >> str('\\') >> newline ).repeat(1) >> singleline_input
101
+ end
102
+
103
+ rule(:command) do
104
+
105
+ # $ some command
106
+ # some output
107
+ ( prompt.as(:prompt) >> space? >> input.as(:input) >> output? ).as(:command)
108
+ end
109
+
110
+ rule(:output) do
111
+
112
+ # output
113
+ prompt.absent? >> text
114
+ end
115
+
116
+ rule(:output?) do
117
+
118
+ #
119
+ # some text
120
+ # some text
121
+ #
122
+ # some text
123
+ ( newline >> ( ( output >> newline ).repeat >> output.maybe ).as(:output) ).maybe
124
+ end
125
+
126
+ rule(:commands) do
127
+ command.repeat
128
+ end
129
+
130
+ rule(:newline) do
131
+ str("\n") | str("\r\n")
132
+ end
133
+
134
+ rule(:space?) do
135
+ match['[:space:]'].repeat
136
+ end
137
+
138
+ root(:commands)
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,42 @@
1
+ require 'redcarpet'
2
+ require 'pygments.rb'
3
+
4
+ module Parade
5
+ module Renderers
6
+ class HTMLwithPygments < Redcarpet::Render::XHTML
7
+
8
+ #
9
+ # When rendering the markdown, the code should be rendered using the
10
+ # Pygments highlight which corresponds to the ghf_marked.css
11
+ #
12
+ # Additionally a class `sh_javascript` or `sh_ruby` is added that will
13
+ # assist in providing a system to provide live interactive elements
14
+ # through the javascript defined in `parade.js`.
15
+ #
16
+ # @param [String] code the fenced code to be highlighted
17
+ # @param [String] language the name of the fenced code
18
+ #
19
+ def block_code(code, language)
20
+ syntax_highlighted_html = Pygments.highlight code, :lexer => language,
21
+ :options => {:encoding => 'utf-8'}
22
+
23
+ syntax_highlighted_html.gsub('class="highlight"',"class=\"highlight sh_#{language}\"")
24
+ end
25
+
26
+ def self.render(content)
27
+ markdown = Redcarpet::Markdown.new(Renderers::HTMLwithPygments,
28
+ :fenced_code_blocks => true,
29
+ :no_intra_emphasis => true,
30
+ :autolink => true,
31
+ :strikethrough => true,
32
+ :lax_html_blocks => true,
33
+ :superscript => true,
34
+ :hard_wrap => true,
35
+ :tables => true,
36
+ :xhtml => true)
37
+ markdown.render(content)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module Parade
3
+ module Renderers
4
+
5
+ #
6
+ # This Renderer will inline the images into content output. Allowing you
7
+ # to create portable documents.
8
+ #
9
+ module InlineImages
10
+
11
+ def self.render(content,options = {})
12
+
13
+ content.gsub(/img src=["']\/?([^\/].*?)["']/) do |image_source|
14
+ image_name = Regexp.last_match(1)
15
+
16
+ base64_data = image_path_to_base64(image_name)
17
+
18
+ if base64_data
19
+ %{img src="#{base64_data}"}
20
+ else
21
+ image_source
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ extend Parade::Helpers::EncodeImage
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module Parade
2
+ module Renderers
3
+
4
+ #
5
+ # Within the markdown you are able to add additional formatting by starting
6
+ # a new line with a period followed by the class name. This is commonly
7
+ # used for writing presenter notes.
8
+ #
9
+ # @example Adding a presenter note within the markdown
10
+ #
11
+ # ## This Slide has important details
12
+ # * Detail 1
13
+ # * Detail 2
14
+ # .notes Ensure that you talk about detail 1 the most!
15
+ #
16
+ class SpecialParagraphRenderer
17
+ def self.render(html_content)
18
+ html_content.gsub(/<p>\.(.*?) /, '<p class="\1">')
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,75 @@
1
+ module Parade
2
+ module Renderers
3
+
4
+ #
5
+ # UpdateImagePaths is used to ensure the img source paths in the HTML
6
+ # content is properly prefaced with the "image" path as that is necessary
7
+ # for the Sinatra server to properly know that it is to return an image.
8
+ #
9
+ # Additional processing of the image is provided if RMagick has been
10
+ # installed. Namely it sets the size correctly.
11
+ #
12
+ class UpdateImagePaths
13
+
14
+ attr_accessor :root_path
15
+
16
+ def initialize(params = {})
17
+ params.each {|k,v| send("#{k}=",v) if respond_to? "#{k}=" }
18
+ end
19
+
20
+ #
21
+ # @param [String] content HTML content that is parsed for image srcs
22
+ # @param [Hash] options additional parameters, at the moment it is unused.
23
+ #
24
+ def self.render(content,options = {})
25
+ self.new(options).render(content)
26
+ end
27
+
28
+ def render(content,options = {})
29
+ render_root_path = options[:root_path] || root_path || "."
30
+
31
+ content.gsub(/img src=["'](?!https?:\/\/)\/?([^\/].*?)["']/) do |image_source|
32
+ image_name = Regexp.last_match(1)
33
+
34
+ html_image_path = File.join("/","image",image_name)
35
+ updated_image_source = %{img src="#{html_image_path}"}
36
+
37
+ html_asset_path = File.join(render_root_path,image_name)
38
+ width, height = get_image_size(html_asset_path)
39
+ updated_image_source << %( width="#{width}" height="#{height}") if width and height
40
+
41
+ updated_image_source
42
+ end
43
+ end
44
+
45
+ def get_image_size(path) ; end
46
+
47
+ if defined?(Magick)
48
+
49
+ def get_image_size(path)
50
+ unless cached_image_size.key?(path)
51
+
52
+ image = Magick::Image.ping(path).first
53
+
54
+ # # don't set a size for svgs so they can expand to fit their container
55
+ if image.mime_type == 'image/svg+xml'
56
+ cached_image_size[path] = [nil, nil]
57
+ else
58
+ cached_image_size[path] = [image.columns, image.rows]
59
+ end
60
+
61
+ end
62
+ cached_image_size[path]
63
+ end
64
+
65
+ def cached_image_size
66
+ @cached_image_size ||= {}
67
+ end
68
+
69
+
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end