chili_pdf 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'wicked_pdf'
3
+ gem 'wicked_pdf', '~> 0.7'
4
+ gem 'nokogiri', '~> 1.4'
4
5
 
5
6
  group :development do
6
7
  gem 'autotest-rails', '~> 4.1'
data/Gemfile.lock CHANGED
@@ -21,6 +21,7 @@ GEM
21
21
  hoe (>= 2.2.0)
22
22
  i18n (0.4.2)
23
23
  json (1.4.6)
24
+ nokogiri (1.4.4)
24
25
  rack (1.0.1)
25
26
  rake (0.8.7)
26
27
  redmine_plugin_support (0.0.4)
@@ -42,7 +43,8 @@ DEPENDENCIES
42
43
  hoe (~> 2.8)
43
44
  hoe-git
44
45
  i18n (= 0.4.2)
46
+ nokogiri (~> 1.4)
45
47
  redmine_plugin_support
46
48
  rspec (= 1.3.1)
47
49
  rspec-rails (= 1.3.2)
48
- wicked_pdf
50
+ wicked_pdf (~> 0.7)
data/History.txt CHANGED
@@ -1,3 +1,20 @@
1
+ === 0.4.0 / 2011-06-18
2
+
3
+ * New features:
4
+ * Simplified customizating styles of of exported PDFs. Added ability to
5
+ insert custom CSS and JavaScript into the DOM before the PDF is
6
+ rendered [closes #12]
7
+ * Added support for images in wiki pages to be exported in PDFs [closes #10]
8
+ (Thanks to @roykolak for the code review!)
9
+ * Added support for rending the HTML used to create the PDF by passing
10
+ "as_html=true" in as a URL param (eg: /Page.pdf?as_html=true) [closes #9]
11
+ * Added nokogiri as a dependency to get around requests for protected
12
+ assets (images, etc) (see issue #10 for details)
13
+
14
+ * Minor enhancements:
15
+ * Fixed image-sizing issue when resolution of image is wider than
16
+ the exported PDF [closes #11]
17
+
1
18
  === 0.3.0 / 2011-06-13
2
19
 
3
20
  * New features
data/Manifest.txt CHANGED
@@ -10,7 +10,11 @@ app/controllers/extended_wiki_controller.rb
10
10
  app/helpers/chili_pdf_helper.rb
11
11
  app/views/extended_wiki/show.pdf.html.erb
12
12
  app/views/layouts/pdf.pdf.erb
13
+ app/views/settings/_chili_pdf_advanced_settings.html.erb
13
14
  app/views/settings/_chili_pdf_settings.html.erb
15
+ app/views/settings/_chili_pdf_typical_settings.html.erb
16
+ assets/javascripts/chili_pdf.js
17
+ assets/stylesheets/chili_pdf_settings_tweaks.css
14
18
  assets/stylesheets/pdf.css
15
19
  autotest/discover.rb
16
20
  config/locales/en.yml
@@ -21,6 +25,7 @@ lib/chili_pdf.rb
21
25
  lib/chili_pdf/config.rb
22
26
  lib/chili_pdf/formatter.rb
23
27
  lib/chili_pdf/string_token.rb
28
+ lib/chili_pdf/tag_mangler.rb
24
29
  lib/chili_pdf/token_manager.rb
25
30
  lib/tasks/chili_pdf_tasks.rb
26
31
  lib/tasks/contributor_tasks.rb
@@ -30,5 +35,7 @@ rails/init.rb
30
35
  test/chili_pdf/config_test.rb
31
36
  test/chili_pdf/formatter_test.rb
32
37
  test/chili_pdf/string_token_test.rb
38
+ test/chili_pdf/tag_mangler_test.rb
33
39
  test/chili_pdf/token_manager_test.rb
34
40
  test/test_helper.rb
41
+ test/unit/helpers/chili_pdf_helper_test.rb
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ChiliPDF Plugin - Flexible PDF exporting for ChiliProject/Redmine
2
2
 
3
- * http://github.com/tomkersten/chili_pdf
3
+ * http://github.com/tomkersten/chili\_pdf
4
4
 
5
5
  ## DESCRIPTION:
6
6
 
@@ -24,13 +24,16 @@ ChiliProject (/Redmine) plugin which implements/enhances PDF-export functionalit
24
24
 
25
25
  ## FEATURES:
26
26
 
27
- 1. Provides PDF export of any project wiki page to PDF with a baseline
28
- stylesheet. The styling can be customized by modifying the "pdf.css'
29
- asset file that ships with the library.
27
+ 1. Provides PDF export of any project wiki page to PDF with a decent
28
+ baseline style out of the box.
29
+ 1. Support for dynamic content in headers and footers administered via the
30
+ plugin configuration page.
31
+ 1. Flexible/easy PDF styling. The styling can be customized by adding your
32
+ own CSS and/or JavaScript on the plugin configuration page.
30
33
 
31
34
  ## SCREENSHOTS:
32
35
 
33
- You can find a few screenshots [here](http://www.flickr.com/photos/tomkersten/sets/72157626827940413/).
36
+ You can find a few screenshots [here](http://www.flickr.com/photos/tomkersten/sets/72157626992576450).
34
37
 
35
38
  ## PROBLEMS:
36
39
 
@@ -55,6 +58,7 @@ You can find a few screenshots [here](http://www.flickr.com/photos/tomkersten/se
55
58
  ## REQUIREMENTS:
56
59
 
57
60
  * wicked\_pdf
61
+ * nokogiri
58
62
 
59
63
  ## INSTALL:
60
64
 
@@ -136,3 +140,7 @@ You can also drop me a message on Twitter [@tomkersten](http://twitter.com/tomke
136
140
  ## LICENSE:
137
141
 
138
142
  Refer to the [LICENSE](https://github.com/tomkersten/chili_pdf/blob/master/LICENSE) file
143
+
144
+ ## Contributors (sorted alphabetically)
145
+
146
+ * Roy Kolak
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ begin
24
24
  self.version = ChiliPDF::VERSION
25
25
  self.extra_rdoc_files = FileList['README.md', 'LICENSE', 'History.txt']
26
26
  self.summary = "ChiliProject (/Redmine) plugin which implements/enhances PDF-export functionality using the Webkit rendering engine."
27
- self.extra_deps = [['wicked_pdf', '0.7.0']]
27
+ self.extra_deps = [['wicked_pdf', '~> 0.7'], ['nokogiri', '~> 1.4']]
28
28
  self.extra_dev_deps = []
29
29
  developer('Tom Kersten', 'tom@whitespur.com')
30
30
  end
@@ -14,7 +14,7 @@ class ExtendedWikiController < WikiController
14
14
 
15
15
  private
16
16
  def formatter
17
- ChiliPDF::Formatter.new(filename, page_title)
17
+ ChiliPDF::Formatter.new(filename, page_title, wants_html_version?)
18
18
  end
19
19
 
20
20
  def filename
@@ -24,4 +24,8 @@ class ExtendedWikiController < WikiController
24
24
  def page_title
25
25
  "#{@project.name}, #{@page.title}"
26
26
  end
27
+
28
+ def wants_html_version?
29
+ @requesting_html_version = params[:as_html] == 'true' || request.format.html?
30
+ end
27
31
  end
@@ -1,10 +1,167 @@
1
1
  module ChiliPdfHelper
2
- # Taken almost verbatim from wicked_pdf gem
3
- def chili_pdf_stylesheets
4
- css_dir = Rails.root.join('public','plugin_assets', 'chili_pdf', 'stylesheets')
5
- css_file_list = Dir.glob("#{css_dir}/*css")
6
- css_file_list.collect { |css_file|
7
- "<style type='text/css'>#{File.read(css_file)}</style>"
2
+ # Public directory of ChiliPDF plugin JavaScript files
3
+ PLUGIN_JS_DIR = Rails.root.join('public','plugin_assets', 'chili_pdf', 'javascripts')
4
+
5
+ # Public directory of ChiliPDF plugin stylesheets
6
+ PLUGIN_CSS_DIR = Rails.root.join('public','plugin_assets', 'chili_pdf', 'stylesheets')
7
+
8
+ # Standard <script>-tag for Prototype JavaScript file
9
+ PROTOTYPE_SCRIPT_TAG = "#{Rails.root}/public/javascripts/prototype.js"
10
+
11
+
12
+ # Public: Generates <link> tags for all CSS files in the
13
+ # plugin_assets/chili_pdf/stylesheets directory, formatting
14
+ # the 'href' attribute value appropriately for HTML or PDF
15
+ # request types.
16
+ #
17
+ # wants_html - specifies whether the 'src' attribute should be formatted
18
+ # for HTML or PDF requests (local vs. relative paths). Added to
19
+ # keep excessive boolean logic out of views.
20
+ #
21
+ # Returns: String of link tags separated by a newline character.
22
+ def chili_pdf_stylesheets(wants_html)
23
+ file_type_list(:css, PLUGIN_CSS_DIR, wants_html) {|asset_path|
24
+ "<link href='#{asset_path}' rel='stylesheet' type='text/css' />\n"
8
25
  }.join("\n")
9
26
  end
27
+
28
+
29
+ # Public: Generate JS <script> tags for all JavaScript files in the
30
+ # plugin_assets/chili_pdf/stylesheets directory, formatting
31
+ # the 'src' attribute value appropriately for HTML or PDF request
32
+ # types
33
+ #
34
+ # wants_html - specifies whether the 'src' attribute should be formatted
35
+ # for HTML or PDF requests (local vs. relative paths). Added to
36
+ # keep excessive boolean logic out of views.
37
+ #
38
+ # Returns: string of <script> tags separated by a newline character
39
+ def chili_pdf_javascripts(wants_html)
40
+ file_type_list(:js, PLUGIN_JS_DIR, wants_html) {|asset_path|
41
+ "<script src='#{asset_path}' type='text/javascript'></script>"
42
+ }.join("\n")
43
+ end
44
+
45
+
46
+ # Public: Converts 'href' attributes of any <link> tags
47
+ # tags to be compatible with the `wkhtmltopdf` executable
48
+ # requirements, using "file://"-format for all local assets.
49
+ #
50
+ # content - the String of HTML content to normalize/update
51
+ # wants_html - specifies whether the 'src' attribute should be formatted
52
+ # for HTML or PDF requests (local vs. relative paths). Added to
53
+ # keep excessive boolean logic out of views.
54
+ #
55
+ # Returns content un-modified if wants_html is true. Otherwise returns
56
+ # the content string with the modified 'href' attribute on all
57
+ # locally-hosted <link>-tags in content.
58
+ def normalize_custom_link_href_tags_in(content, wants_html = false)
59
+ update_tag_attribute(:link, :href, content, wants_html)
60
+ end
61
+
62
+
63
+ # Public: Converts 'src' attributes of any <script> tags (with a 'src'
64
+ # attribute) to be compatible with the `wkhtmltopdf` executable
65
+ # requirements, using "file://"-format for all local assets.
66
+ #
67
+ # content - the String of HTML content to normalize/update
68
+ # wants_html - specifies whether the 'src' attribute should be formatted
69
+ # for HTML or PDF requests (local vs. relative paths). Added to
70
+ # keep excessive boolean logic out of views.
71
+ #
72
+ # Returns content un-modified if wants_html is true. Otherwise returns
73
+ # the content string with the modified 'src' attribute on all
74
+ # locally-hosted <script>-tags in content.
75
+ def normalize_custom_js_src_tags_in(content, wants_html = false)
76
+ update_tag_attribute(:script, :src, content, wants_html)
77
+ end
78
+
79
+
80
+ # Public: Converts 'src' attributes of any <img> tags to be compatible with
81
+ # the `wkhtmltopdf` executable requirements, using "file://"-format
82
+ # for all local assets.
83
+ #
84
+ # content - the String of HTML content to normalize/update
85
+ # wants_html - specifies whether the 'src' attribute should be formatted
86
+ # for HTML or PDF requests (local vs. relative paths). Added to
87
+ # keep excessive boolean logic out of views.
88
+ #
89
+ # Returns content un-modified if wants_html is true. Otherwise returns
90
+ # the content string with the modified 'src' attribute on all
91
+ # locally-hosted <img>-tags in content.
92
+ def update_img_src_tags_of(content, wants_html = false)
93
+ update_tag_attribute(:img, :src, content, wants_html)
94
+ end
95
+
96
+
97
+ private
98
+ # Updates the value of the specified attribute of any `tag_type` tags
99
+ # contained in `content` to be compatible with the `wkhtmltopdf`
100
+ # executable. If `wants_html` is falsey, no modifications are made
101
+ # to content.
102
+ #
103
+ # tag_type - String-link object which returns the tag to look for in
104
+ # 'content' when #to_s is called on it.
105
+ # content - String of the HTML content to search for `tag_type' in
106
+ # wants_html - specifies whether the attribute should be formatted
107
+ # for HTML or PDF requests (local vs. relative paths). Added to
108
+ # keep excessive boolean logic out of views.
109
+ def update_tag_attribute(tag_type, attribute, content, wants_html)
110
+ return content if wants_html
111
+
112
+ doc = ::Nokogiri::HTML(content)
113
+ doc.xpath("//#{tag_type.to_s}[@#{attribute.to_s}]").each do |a_tag|
114
+ a_tag["#{attribute.to_s}"] = mangle(a_tag["#{attribute.to_s}"])
115
+ end
116
+ doc.to_s
117
+ end
118
+
119
+
120
+ # Generate list of content based on files with the specified file extension
121
+ # in the specified source directory. The object passed into the block will
122
+ # be the path to an individual file path in either HTML- or PDF-request
123
+ # compatible form (file://-based or relative-url based). Useful for
124
+ # generating a series of tags for all files matching a particular file type
125
+ # in a specified directory.
126
+ #
127
+ # file_ext - the file extension to search for in the src_dir
128
+ # src_dir - the directory to search for file with the specified
129
+ # file extension (file_ext)
130
+ # wants_html - specifies whether the 'src' attribute should be formatted
131
+ # for HTML or PDF requests (local vs. relative paths). Added to
132
+ # keep excessive boolean logic out of views.
133
+ # &block - code to execute on each matching filename (filename is
134
+ # passed in as a parameter to &block)
135
+ # Returns an Array of the results of the &block executions.
136
+ def file_type_list(file_ext, src_dir, wants_html, &block)
137
+ # We want/need to prepend the Prototype script-tag before all other script-tags
138
+ file_list = file_ext.to_s == "js" ? [PROTOTYPE_SCRIPT_TAG] : []
139
+
140
+ file_list.push(*Dir.glob("#{src_dir}/*#{file_ext.to_s}")).collect do |file_path|
141
+ asset_path = file_path.to_s.sub(/^#{Rails.root}\/public/, '')
142
+ asset_path = mangle(asset_path) unless wants_html
143
+ yield asset_path
144
+ end
145
+ end
146
+
147
+ # Converts the specified String to PDF-format-friendly version of itself.
148
+ # Supports the '/attachments/:id/:filename' and '/attachments/download/:id' routes
149
+ # of ChiliProject as well as standard static assets (nested under RAILS_ROOT/public).
150
+ #
151
+ # content - String to convert
152
+ #
153
+ # Examples
154
+ #
155
+ # mangle('/stylesheets/application.css')
156
+ # => "file:///path/to/rails_root/public/stylesheets/application.css"
157
+ #
158
+ # mangle('/attachments/1/image.png')
159
+ # => "file:///path/to/rails_root/files/38278327_image.png"
160
+ #
161
+ # Returns modified String, unless requested asset either doesn't exist
162
+ # or is an invalid request (to, say, an asset located above
163
+ # the 'RAILS_ROOT/public' sub-directory.
164
+ def mangle(content)
165
+ TagMangler.new(content).to_local_src
166
+ end
10
167
  end
@@ -1,5 +1,9 @@
1
1
  <% content_for :header_tags do %>
2
- <%= chili_pdf_stylesheets %>
2
+ <%= chili_pdf_stylesheets(@requesting_html_version) %>
3
+ <%= chili_pdf_javascripts(@requesting_html_version) %>
4
+ <%= normalize_custom_link_href_tags_in(ChiliPDF::Config.custom_css, @requesting_html_version) %>
5
+ <%= normalize_custom_js_src_tags_in(ChiliPDF::Config.custom_js, @requesting_html_version) %>
3
6
  <% end %>
4
7
 
5
- <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
8
+ <%- html_content = textilizable(@content.text, :attachments => @content.page.attachments) %>
9
+ <%= update_img_src_tags_of(html_content, @requesting_html_version) %>
@@ -16,7 +16,7 @@
16
16
  <%= yield(:header_tags) %>
17
17
  </head>
18
18
 
19
- <body>
19
+ <body id="custom-pdf-styles">
20
20
  <%= yield(:layout) %>
21
21
  </body>
22
22
  </html>
@@ -0,0 +1,13 @@
1
+ <p class="chili-pdf-instructions">
2
+ You can add custom CSS & JavaScript which will be applied to your PDF before saving.
3
+ </p>
4
+
5
+ <p>
6
+ <label><%= l(:label_custom_css) %></label>
7
+ <%= text_area_tag "settings[#{ChiliPDF::Config::CUSTOM_CSS_KEYNAME}]", ChiliPDF::Config.custom_css %>
8
+ </p>
9
+
10
+ <p>
11
+ <label><%= l(:label_custom_js) %></label>
12
+ <%= text_area_tag "settings[#{ChiliPDF::Config::CUSTOM_JS_KEYNAME}]", ChiliPDF::Config.custom_js %>
13
+ </p>
@@ -1,82 +1,9 @@
1
1
  <% content_for :header_tags do %>
2
- <%= stylesheet_link_tag '/plugin_assets/chili_pdf/stylesheets/pdf' %>
2
+ <%= stylesheet_link_tag '/plugin_assets/chili_pdf/stylesheets/chili_pdf_settings_tweaks' %>
3
3
  <% end %>
4
4
 
5
- <p>
6
- <label for='settings_<%= ChiliPDF::Config::HEADER_ENABLED_KEYNAME %>'><%= l(:header_enabled_label) %></label>
7
- <%= check_box_tag "settings[#{ChiliPDF::Config::HEADER_ENABLED_KEYNAME}]", ChiliPDF::Config::ENABLED_VALUE, ChiliPDF::Config.header_enabled? %>
8
- </p>
5
+ <%= render_tabs([
6
+ {:name => 'typical_settings', :partial => 'settings/chili_pdf_typical_settings', :label => :typical_plugin_settings},
7
+ {:name => 'advanced_settings', :partial => 'settings/chili_pdf_advanced_settings', :label => :advanced_plugin_settings},
8
+ ]) %>
9
9
 
10
- <p>
11
- <label for='settings_<%= ChiliPDF::Config::FOOTER_ENABLED_KEYNAME %>'><%= l(:footer_enabled_label) %></label>
12
- <%= check_box_tag "settings[#{ChiliPDF::Config::FOOTER_ENABLED_KEYNAME}]", ChiliPDF::Config::ENABLED_VALUE, ChiliPDF::Config.footer_enabled? %>
13
- </p>
14
-
15
- <h3>Custom Header/Footer Content</h3>
16
-
17
- <h4>Rules</h4>
18
- <ol>
19
- <li>Any "plain text" will render, as is...</li>
20
- <li>
21
- There are a few 'variables' you can use to dynamically replace content. For example,
22
- you can add the current date to any page.
23
- </li>
24
- <li>All input will be escaped HTML, so injecting dynamic content via JavaScript will not work.</li>
25
- </ol>
26
-
27
- <table>
28
- <thead>
29
- <tr>
30
- <td></td>
31
- <td>Left</td>
32
- <td>Center</td>
33
- <td>Right</td>
34
- </tr>
35
- </thead>
36
- <tbody>
37
- <tr>
38
- <td>Header</td>
39
- <td>
40
- <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_LEFT_KEYNAME}]", ChiliPDF::Config.header_values[:left] %>
41
- </td>
42
- <td>
43
- <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_CENTER_KEYNAME}]", ChiliPDF::Config.header_values[:center] %>
44
- </td>
45
- <td>
46
- <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_RIGHT_KEYNAME}]", ChiliPDF::Config.header_values[:right] %>
47
- </td>
48
- </tr>
49
- <tr>
50
- <td>Footer</td>
51
- <td>
52
- <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_LEFT_KEYNAME}]", ChiliPDF::Config.footer_values[:left] %>
53
- </td>
54
- <td>
55
- <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_CENTER_KEYNAME}]", ChiliPDF::Config.footer_values[:center] %>
56
- </td>
57
- <td>
58
- <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_RIGHT_KEYNAME}]", ChiliPDF::Config.footer_values[:right] %>
59
- </td>
60
- </tr>
61
- </tbody>
62
- </table>
63
-
64
- <div id="pdf-token-help">
65
- <h4>Dynamic text legend</h4>
66
- <table>
67
- <thead>
68
- <tr>
69
- <td>Enter this</td>
70
- <td>...to show this</td>
71
- </tr>
72
- </thead>
73
- <tbody>
74
- <%- ChiliPDF::TokenManager.tokens.each do |token| %>
75
- <tr>
76
- <td class="token"><%= token.matcher_with_delimiters %></td>
77
- <td class="description"><%= token.description %></td>
78
- </tr>
79
- <%- end %>
80
- </tbody>
81
- </table>
82
- </div>
@@ -0,0 +1,76 @@
1
+ <p class="chili-pdf-instructions">
2
+ <span class="tip-label">Pro Tip:</span>
3
+ You can see what impact your settings have on exported items by appending a
4
+ "<em>.pdf?as_html=true</em>" to the URL of any wiki page. This will give you an
5
+ idea of what your style/behavior changes will look like (without headers, margins,
6
+ et cetera).
7
+ </p>
8
+
9
+ <p>
10
+ <label for='settings_<%= ChiliPDF::Config::HEADER_ENABLED_KEYNAME %>'><%= l(:header_enabled_label) %></label>
11
+ <%= check_box_tag "settings[#{ChiliPDF::Config::HEADER_ENABLED_KEYNAME}]", ChiliPDF::Config::ENABLED_VALUE, ChiliPDF::Config.header_enabled? %>
12
+ </p>
13
+
14
+ <p>
15
+ <label for='settings_<%= ChiliPDF::Config::FOOTER_ENABLED_KEYNAME %>'><%= l(:footer_enabled_label) %></label>
16
+ <%= check_box_tag "settings[#{ChiliPDF::Config::FOOTER_ENABLED_KEYNAME}]", ChiliPDF::Config::ENABLED_VALUE, ChiliPDF::Config.footer_enabled? %>
17
+ </p>
18
+
19
+ <h3>Custom Header/Footer Content</h3>
20
+
21
+ <table>
22
+ <thead>
23
+ <tr>
24
+ <td></td>
25
+ <td>Left</td>
26
+ <td>Center</td>
27
+ <td>Right</td>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+ <tr>
32
+ <td>Header</td>
33
+ <td>
34
+ <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_LEFT_KEYNAME}]", ChiliPDF::Config.header_values[:left] %>
35
+ </td>
36
+ <td>
37
+ <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_CENTER_KEYNAME}]", ChiliPDF::Config.header_values[:center] %>
38
+ </td>
39
+ <td>
40
+ <%= text_field_tag "settings[#{ChiliPDF::Config::HEADER_RIGHT_KEYNAME}]", ChiliPDF::Config.header_values[:right] %>
41
+ </td>
42
+ </tr>
43
+ <tr>
44
+ <td>Footer</td>
45
+ <td>
46
+ <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_LEFT_KEYNAME}]", ChiliPDF::Config.footer_values[:left] %>
47
+ </td>
48
+ <td>
49
+ <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_CENTER_KEYNAME}]", ChiliPDF::Config.footer_values[:center] %>
50
+ </td>
51
+ <td>
52
+ <%= text_field_tag "settings[#{ChiliPDF::Config::FOOTER_RIGHT_KEYNAME}]", ChiliPDF::Config.footer_values[:right] %>
53
+ </td>
54
+ </tr>
55
+ </tbody>
56
+ </table>
57
+
58
+ <div id="pdf-token-help">
59
+ <h4>Dynamic text legend</h4>
60
+ <table>
61
+ <thead>
62
+ <tr>
63
+ <td>Enter this</td>
64
+ <td>...to show this</td>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <%- ChiliPDF::TokenManager.tokens.each do |token| %>
69
+ <tr>
70
+ <td class="token"><%= token.matcher_with_delimiters %></td>
71
+ <td class="description"><%= token.description %></td>
72
+ </tr>
73
+ <%- end %>
74
+ </tbody>
75
+ </table>
76
+ </div>
File without changes
@@ -0,0 +1,10 @@
1
+ em {font-style: italic;}
2
+ textarea {width: 600px; height: 200px;}
3
+
4
+ p.chili-pdf-instructions {padding-left: 0;}
5
+ .tip-label {font-weight: bold; text-decoration: underline;}
6
+
7
+ #pdf-token-help {margin-top: 20px;}
8
+ #pdf-token-help table {width: 100%; border: 1px #AAA solid;}
9
+ #pdf-token-help td {border-bottom: 1px dotted #CCC;}
10
+ #pdf-token-help thead td {font-weight: bold; border-bottom: 2px solid #CCC;}
@@ -33,12 +33,4 @@ li { padding: 0.1em; }
33
33
  ol li {list-style-type: decimal;}
34
34
  ul li {list-style-type: disc;}
35
35
  h1, h2 {font-weight: bold;}
36
-
37
- #pdf-token-help {
38
- margin-top: 20px;
39
- }
40
-
41
- #pdf-token-help table {width: 100%; border: 1px #AAA solid;}
42
- #pdf-token-help td {border-bottom: 1px dotted #CCC;}
43
-
44
- #pdf-token-help thead td {font-weight: bold; border-bottom: 2px solid #CCC;}
36
+ img {max-width: 100%;}
@@ -3,3 +3,7 @@ en:
3
3
  chili_pdf_instructions: 'You can customize the behavior of the ChiliPDf plugin with the settings below'
4
4
  header_enabled_label: Display page header?
5
5
  footer_enabled_label: Display page footer?
6
+ typical_plugin_settings: Typical Settings
7
+ advanced_plugin_settings: Technical Settings
8
+ label_custom_css: Custom CSS
9
+ label_custom_js: Custom JavaScript
data/config/routes.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  ActionController::Routing::Routes.draw do |map|
2
+ map.connect 'projects/:project_id/wiki.pdf', :controller => 'extended_wiki', :action => 'show', :format => 'pdf'
2
3
  map.connect 'projects/:project_id/wiki/:id.pdf', :controller => 'extended_wiki', :action => 'show', :format => 'pdf'
3
4
  end
data/init.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'redmine'
2
2
  require 'chili_pdf'
3
- require 'wicked_pdf'
3
+ require 'wicked_pdf' unless defined?(WickedPdf)
4
+ require 'nokogiri' unless defined?(Nokogiri)
4
5
  require 'dispatcher'
5
6
 
6
7
  Redmine::Plugin.register :chili_pdf do
data/lib/chili_pdf.rb CHANGED
@@ -2,7 +2,8 @@ require 'chili_pdf/config'
2
2
  require 'chili_pdf/token_manager'
3
3
  require 'chili_pdf/formatter'
4
4
  require 'chili_pdf/string_token'
5
+ require 'chili_pdf/tag_mangler'
5
6
 
6
7
  module ChiliPDF
7
- VERSION = '0.3.0'
8
+ VERSION = '0.4.0'
8
9
  end
@@ -7,6 +7,8 @@ module ChiliPDF
7
7
  DISABLED_VALUE = '0'
8
8
  FOOTER_ENABLED_KEYNAME = 'footer_enabled'
9
9
  HEADER_ENABLED_KEYNAME = 'header_enabled'
10
+ CUSTOM_CSS_KEYNAME = 'custom_css'
11
+ CUSTOM_JS_KEYNAME = 'custom_javascript'
10
12
 
11
13
  HEADER_LEFT_KEYNAME = :header_content_left
12
14
  HEADER_CENTER_KEYNAME = :header_content_center
@@ -21,6 +23,25 @@ module ChiliPDF
21
23
  FOOTER_LEFT_DEFAULT_VALUE = '{{datestamp}}'
22
24
  FOOTER_CENTER_DEFAULT_VALUE = ''
23
25
  FOOTER_RIGHT_DEFAULT_VALUE = '{{current_page}}/{{total_pages}}'
26
+ CUSTOM_CSS_DEFAULT_VALUE = <<END_OF_CSS_DEF
27
+ <!-- stylesheet link example, uncomment & modify if you like -->
28
+ <!-- <link href='/stylesheets/your_custom.css' rel='stylesheet' type='text/css' />
29
+
30
+ <!-- inline example -->
31
+ <style type="text/css">
32
+ //#custom-pdf-styles h2 {color: red;}
33
+ </style>
34
+ END_OF_CSS_DEF
35
+
36
+ CUSTOM_JS_DEFAULT_VALUE = <<END_OF_JS_DEF
37
+ <!-- Script tag link example. Uncomment & modify if you like. -->
38
+ <!-- <script src='/javascripts/your_custom.js' type='text/javascript' />
39
+
40
+ <!-- Inline JavaScript example -->
41
+ <script type="text/javascript">
42
+ // Your custom-inline JS here
43
+ </script>
44
+ END_OF_JS_DEF
24
45
 
25
46
  def defaults
26
47
  {
@@ -31,7 +52,9 @@ module ChiliPDF
31
52
  HEADER_RIGHT_KEYNAME => HEADER_RIGHT_DEFAULT_VALUE,
32
53
  FOOTER_LEFT_KEYNAME => FOOTER_LEFT_DEFAULT_VALUE,
33
54
  FOOTER_CENTER_KEYNAME => FOOTER_CENTER_DEFAULT_VALUE,
34
- FOOTER_RIGHT_KEYNAME => FOOTER_RIGHT_DEFAULT_VALUE
55
+ FOOTER_RIGHT_KEYNAME => FOOTER_RIGHT_DEFAULT_VALUE,
56
+ CUSTOM_CSS_KEYNAME => CUSTOM_CSS_DEFAULT_VALUE,
57
+ CUSTOM_JS_KEYNAME => CUSTOM_JS_DEFAULT_VALUE
35
58
  }
36
59
  end
37
60
 
@@ -72,6 +95,22 @@ module ChiliPDF
72
95
  default_footer_values.merge(stored_footer_settings)
73
96
  end
74
97
 
98
+ def custom_css
99
+ if plugin_settings[CUSTOM_CSS_KEYNAME].blank?
100
+ CUSTOM_CSS_DEFAULT_VALUE
101
+ else
102
+ plugin_settings[CUSTOM_CSS_KEYNAME]
103
+ end
104
+ end
105
+
106
+ def custom_js
107
+ if plugin_settings[CUSTOM_JS_KEYNAME].blank?
108
+ CUSTOM_JS_DEFAULT_VALUE
109
+ else
110
+ plugin_settings[CUSTOM_JS_KEYNAME]
111
+ end
112
+ end
113
+
75
114
  private
76
115
  def default_header_values
77
116
  {:left => HEADER_LEFT_DEFAULT_VALUE,
@@ -15,9 +15,10 @@ module ChiliPDF
15
15
  :description => "The project & wiki page name (eg: 'My Project, Wiki Page Title')"}}
16
16
  end
17
17
 
18
- def initialize(filename, title = nil)
18
+ def initialize(filename, title = nil, render_html_version = nil)
19
19
  @page_title = title
20
20
  @filename = filename
21
+ @allow_debugging = render_html_version
21
22
 
22
23
  # TODO: Hack...need to come up with better approach for this...
23
24
  TokenManager.add_token_definition do
@@ -31,6 +32,7 @@ module ChiliPDF
31
32
  :pdf => @filename,
32
33
  :template => view_template,
33
34
  :page_size => DEFAULT_PAGE_SIZE,
35
+ :show_as_html => render_as_html?,
34
36
  :margin => {
35
37
  :top => DEFAULT_MARGIN,
36
38
  :bottom => DEFAULT_MARGIN,
@@ -76,5 +78,9 @@ module ChiliPDF
76
78
  def view_template
77
79
  DEFAULT_VIEW_TEMPLATE
78
80
  end
81
+
82
+ def render_as_html?
83
+ !@allow_debugging.blank?
84
+ end
79
85
  end
80
86
  end
@@ -0,0 +1,65 @@
1
+ class TagMangler
2
+ def initialize(src)
3
+ @src_attribute = src
4
+ end
5
+
6
+ def to_local_src
7
+ full_file_path.blank? ? @src_attribute : "file://#{full_file_path}"
8
+ end
9
+
10
+ private
11
+ def full_file_path
12
+ if requesting_valid_static_asset?
13
+ requested_path
14
+ elsif requesting_attachment? && !attachment.blank?
15
+ attachment.diskfile
16
+ end
17
+ end
18
+
19
+ def attachment
20
+ Attachment.find_by_id(attachment_id)
21
+ end
22
+
23
+ def requesting_attachment?
24
+ !attachment_id.blank?
25
+ end
26
+
27
+ def requesting_valid_static_asset?
28
+ requested_asset_under_public_dir? && static_asset_exists?
29
+ end
30
+
31
+ def static_asset_exists?
32
+ File.exists?(requested_path)
33
+ end
34
+
35
+ def requested_path
36
+ File.expand_path(File.join(public_path, @src_attribute))
37
+ end
38
+
39
+ def public_path
40
+ File.expand_path(File.join(Rails.root, 'public'))
41
+ end
42
+
43
+ def requested_asset_under_public_dir?
44
+ requested_path.match(/^#{public_path}/)
45
+ end
46
+
47
+ # Pull the specified attachment ID out of the @src_attribute
48
+ # if it is in one of the 'standad' URL formats
49
+ # (ie: the :id field from the examples below)
50
+ #
51
+ # Example URLs:
52
+ # /attachments/:id/:filename
53
+ # /attachments/download/:id
54
+ #
55
+ # Returns the specified id as a string if a valid one is present
56
+ # Returns nil otherwise
57
+ def attachment_id
58
+ regexp = Regexp.new(/\/?attachments(?:\/download)?\/(\d+)\/?.*/)
59
+ @src_attribute.match(regexp) && $1
60
+ end
61
+
62
+
63
+ end
64
+
65
+
@@ -30,6 +30,23 @@ class FormatterTest < Test::Unit::TestCase
30
30
  assert_equal default_margins, @formatter.render_options[:margin]
31
31
  end
32
32
 
33
+ context "enabling/disabling viewing the underlying HTML of the PDF" do
34
+ should "set :show_as_html key to true when true is specified" do
35
+ formatter = Formatter.new('filename.pdf', 'title', true)
36
+ assert formatter.render_options[:show_as_html]
37
+ end
38
+
39
+ should "set :show_as_html key to false when false is specified" do
40
+ formatter = Formatter.new('filename.pdf', 'title', false)
41
+ assert !formatter.render_options[:show_as_html]
42
+ end
43
+
44
+ should "set :show_as_html key to false as the default" do
45
+ formatter = Formatter.new('filename.pdf', 'title')
46
+ assert !formatter.render_options[:show_as_html]
47
+ end
48
+ end
49
+
33
50
  context 'when footers are enabled' do
34
51
  setup do
35
52
  enable_footers
@@ -0,0 +1,115 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ def make_mangler_with(asset_path)
4
+ TagMangler.new(asset_path)
5
+ end
6
+
7
+ # Stolen from the Rails.root test_helper...
8
+ # not sure why they are not being included in here yet
9
+ def mock_file
10
+ file = 'a_file.png'
11
+ file.stubs(:size).returns(32)
12
+ file.stubs(:original_filename).returns('a_file.png')
13
+ file.stubs(:content_type).returns('image/png')
14
+ file.stubs(:read).returns(false)
15
+ file
16
+ end
17
+
18
+ class TokenManagerTest < Test::Unit::TestCase
19
+ context "#to_local_src" do
20
+ context "when requesting a static asset" do
21
+ setup do
22
+ @requested_asset = "../Rakefile"
23
+ @mangler = make_mangler_with(@requested_asset)
24
+ end
25
+
26
+ context "which is not nested under the 'public' directory of the application" do
27
+ should "return the original value without any modifications" do
28
+ assert_equal @requested_asset, @mangler.to_local_src
29
+ end
30
+ end
31
+
32
+ context "which does not exist on the filesystem" do
33
+ setup do
34
+ @requested_asset = 'stylesheets/faux_css_file_fildjakfldsa.css'
35
+ @mangler = make_mangler_with(@requested_asset)
36
+ end
37
+
38
+ should "return the original value without any modifications" do
39
+ assert_equal @requested_asset, @mangler.to_local_src
40
+ end
41
+ end
42
+
43
+ context "which does exist on the filesystem" do
44
+ setup do
45
+ # slightly brittle, but assuming application.css
46
+ # will always ship w/ app...
47
+ @requested_asset = 'stylesheets/application.css'
48
+ @mangler = make_mangler_with(@requested_asset)
49
+ end
50
+
51
+ should "return the full (local) path to the file prepended with 'file://'" do
52
+ css_path = File.join(Rails.root, 'public', 'stylesheets', 'application.css')
53
+ assert_equal "file://#{css_path}", @mangler.to_local_src
54
+ end
55
+ end
56
+ end
57
+
58
+ context "when requesting an Attachment" do
59
+ context "using a URI in the form of 'attachments/download/200'"do
60
+ setup do
61
+ @requested_asset = '/attachments/download/200'
62
+ @mangler = make_mangler_with(@requested_asset)
63
+ end
64
+
65
+ should "search for an attachment with an id of '200'" do
66
+ Attachment.expects(:find).with(:first, {:conditions => {:id => '200'}})
67
+ @mangler.to_local_src
68
+ end
69
+ end
70
+
71
+ context "using a URI in the form of 'attachments/2/after.png'"do
72
+ setup do
73
+ @requested_asset = 'attachments/2/after.png'
74
+ @mangler = make_mangler_with(@requested_asset)
75
+ end
76
+
77
+ should "search for an attachment with an id of '2'" do
78
+ Attachment.expects(:find).with(:first, :conditions => {:id => '2'})
79
+ @mangler.to_local_src
80
+ end
81
+ end
82
+
83
+ context "which does not exist" do
84
+ setup do
85
+ @requested_asset = '/attachments/download/1'
86
+ @mangler = make_mangler_with(@requested_asset)
87
+ Attachment.expects(:find).returns(nil)
88
+ end
89
+
90
+ should "return the original value without any modifications" do
91
+ assert_equal @requested_asset, @mangler.to_local_src
92
+ end
93
+ end
94
+
95
+ context "which exists" do
96
+ setup do
97
+ # Set up faux local file location & Attachment instance
98
+ @local_path = '/a/local/path/to/file.png'
99
+ @req_attachment = mock_file
100
+ @req_attachment.stubs(:diskfile).returns(@local_path)
101
+
102
+ # Stub finding the instance
103
+ Attachment.stubs(:find).returns(@req_attachment)
104
+
105
+ @requested_asset = '/attachments/download/200'
106
+ @mangler = make_mangler_with(@requested_asset)
107
+ end
108
+
109
+ should "render the full (local) path to the file" do
110
+ assert_equal "file://#{@local_path}", @mangler.to_local_src
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+
3
+ class ChiliPdfHelperTest < HelperTestCase
4
+ include ChiliPdfHelper
5
+
6
+ context "#chili_pdf_stylesheets" do
7
+ should "include the pdf.css stylesheet" do
8
+ assert_match %r(<link.*href=['"].*pdf\.css['"].*>), chili_pdf_stylesheets(false)
9
+ end
10
+
11
+ context "when making an HTML request" do
12
+ should "set the vale of the 'href' attribute to a relative URL" do
13
+ assert_match %r(<link.*href=['"]/.*\.css['"].*>), chili_pdf_stylesheets(true)
14
+ end
15
+ end
16
+
17
+ context "when making a PDF request" do
18
+ should "set the vale of the 'href' attribute to a file://-based location" do
19
+ assert_match %r(<link.*href=['"]file://.*\.css['"].*>), chili_pdf_stylesheets(false)
20
+ end
21
+ end
22
+ end
23
+
24
+ context "#chili_pdf_javascripts" do
25
+ should "include the prototype JavaScript library" do
26
+ assert_match %r(<script.*src=['"].*prototype\.js['"].*></script>), chili_pdf_javascripts(false)
27
+ end
28
+
29
+ context "when making an HTML request" do
30
+ should "set the vale of the 'src' attribute to a relative URL" do
31
+ assert_match %r(<script.*src=['"]/.*\.js['"].*></script>), chili_pdf_javascripts(true)
32
+ end
33
+ end
34
+
35
+ context "when making a PDF request" do
36
+ should "set the vale of the 'src' attribute to a file://-based location" do
37
+ assert_match %r(<script.*src=['"]file://.*\.js['"].*></script>), chili_pdf_javascripts(false)
38
+ end
39
+ end
40
+ end
41
+
42
+ context "#normalize_custom_link_href_tags_in" do
43
+ setup do
44
+ @html = "<link href='/stylesheets/application.css' />"
45
+ end
46
+
47
+ context "when making an HTML request" do
48
+ should "set the vale of the 'href' attribute to a relative URL" do
49
+ results = normalize_custom_link_href_tags_in(@html, true)
50
+ assert_match %r(<link.*href=['"]/stylesheets/application\.css['"].*>), results
51
+ end
52
+ end
53
+
54
+ context "when making a PDF request" do
55
+ should "set the vale of the 'href' attribute to a file://-based location" do
56
+ results = normalize_custom_link_href_tags_in(@html, false)
57
+ assert_match %r(<link.*href=['"]file://.*/stylesheets/application\.css['"].*>), results
58
+ end
59
+ end
60
+ end
61
+
62
+ context "#normalize_custom_js_src_tags_in" do
63
+ setup do
64
+ @html = "<script src='/plugin_assets/chili_pdf/javascripts/chili_pdf.js'></script>"
65
+ end
66
+
67
+ context "when making an HTML request" do
68
+ should "set the vale of the 'src' attribute to a relative URL" do
69
+ results = normalize_custom_js_src_tags_in(@html, true)
70
+ assert_match %r(<script.*src=['"]/plugin_assets/chili_pdf/javascripts/chili_pdf\.js['"].*></script>), results
71
+ end
72
+ end
73
+
74
+ context "when making a PDF request" do
75
+ should "set the vale of the 'src' attribute to a file://-based location" do
76
+ results = normalize_custom_js_src_tags_in(@html, false)
77
+ assert_match %r(<script.*src=['"]file://.*/plugin_assets/chili_pdf/javascripts/chili_pdf\.js['"].*></script>), results
78
+ end
79
+ end
80
+ end
81
+
82
+ context "#update_img_src_tags_of" do
83
+ setup do
84
+ @html = "<img src='/images/cancel.png'>"
85
+ end
86
+
87
+ context "when making an HTML request" do
88
+ should "set the vale of the 'src' attribute to a relative URL" do
89
+ results = update_img_src_tags_of(@html, true)
90
+ assert_match %r(<img.*src=['"]/images/cancel\.png['"].*>), results
91
+ end
92
+ end
93
+
94
+ context "when making a PDF request" do
95
+ should "set the vale of the 'src' attribute to a file://-based location" do
96
+ results = update_img_src_tags_of(@html, false)
97
+ assert_match %r(<img.*src=['"]file://.*/images/cancel\.png['"].*>), results
98
+ end
99
+ end
100
+ end
101
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chili_pdf
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tom Kersten
@@ -36,7 +36,7 @@ cert_chain:
36
36
  NVADJA==
37
37
  -----END CERTIFICATE-----
38
38
 
39
- date: 2011-06-13 00:00:00 -05:00
39
+ date: 2011-06-18 00:00:00 -05:00
40
40
  default_executable:
41
41
  dependencies:
42
42
  - !ruby/object:Gem::Dependency
@@ -45,20 +45,34 @@ dependencies:
45
45
  requirement: &id001 !ruby/object:Gem::Requirement
46
46
  none: false
47
47
  requirements:
48
- - - "="
48
+ - - ~>
49
49
  - !ruby/object:Gem::Version
50
- hash: 3
50
+ hash: 5
51
51
  segments:
52
52
  - 0
53
53
  - 7
54
- - 0
55
- version: 0.7.0
54
+ version: "0.7"
56
55
  type: :runtime
57
56
  version_requirements: *id001
58
57
  - !ruby/object:Gem::Dependency
59
- name: hoe
58
+ name: nokogiri
60
59
  prerelease: false
61
60
  requirement: &id002 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ hash: 7
66
+ segments:
67
+ - 1
68
+ - 4
69
+ version: "1.4"
70
+ type: :runtime
71
+ version_requirements: *id002
72
+ - !ruby/object:Gem::Dependency
73
+ name: hoe
74
+ prerelease: false
75
+ requirement: &id003 !ruby/object:Gem::Requirement
62
76
  none: false
63
77
  requirements:
64
78
  - - ">="
@@ -70,7 +84,7 @@ dependencies:
70
84
  - 0
71
85
  version: 2.8.0
72
86
  type: :development
73
- version_requirements: *id002
87
+ version_requirements: *id003
74
88
  description: ChiliProject (/Redmine) plugin which implements/enhances PDF-export functionality using the Webkit rendering engine (via the 'wkhtmltopdf' executable).
75
89
  email:
76
90
  - tom@whitespur.com
@@ -96,7 +110,11 @@ files:
96
110
  - app/helpers/chili_pdf_helper.rb
97
111
  - app/views/extended_wiki/show.pdf.html.erb
98
112
  - app/views/layouts/pdf.pdf.erb
113
+ - app/views/settings/_chili_pdf_advanced_settings.html.erb
99
114
  - app/views/settings/_chili_pdf_settings.html.erb
115
+ - app/views/settings/_chili_pdf_typical_settings.html.erb
116
+ - assets/javascripts/chili_pdf.js
117
+ - assets/stylesheets/chili_pdf_settings_tweaks.css
100
118
  - assets/stylesheets/pdf.css
101
119
  - autotest/discover.rb
102
120
  - config/locales/en.yml
@@ -107,6 +125,7 @@ files:
107
125
  - lib/chili_pdf/config.rb
108
126
  - lib/chili_pdf/formatter.rb
109
127
  - lib/chili_pdf/string_token.rb
128
+ - lib/chili_pdf/tag_mangler.rb
110
129
  - lib/chili_pdf/token_manager.rb
111
130
  - lib/tasks/chili_pdf_tasks.rb
112
131
  - lib/tasks/contributor_tasks.rb
@@ -116,10 +135,12 @@ files:
116
135
  - test/chili_pdf/config_test.rb
117
136
  - test/chili_pdf/formatter_test.rb
118
137
  - test/chili_pdf/string_token_test.rb
138
+ - test/chili_pdf/tag_mangler_test.rb
119
139
  - test/chili_pdf/token_manager_test.rb
120
140
  - test/test_helper.rb
141
+ - test/unit/helpers/chili_pdf_helper_test.rb
121
142
  has_rdoc: true
122
- homepage: http://github.com/tomkersten/chili_pdf
143
+ homepage: http://github.com/tomkersten/chili\_pdf
123
144
  licenses: []
124
145
 
125
146
  post_install_message:
metadata.gz.sig CHANGED
Binary file