govspeak 4.0.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +12 -0
- data/bin/govspeak +8 -0
- data/lib/govspeak.rb +51 -23
- data/lib/govspeak/cli.rb +51 -0
- data/lib/govspeak/post_processor.rb +26 -0
- data/lib/govspeak/version.rb +1 -1
- data/lib/presenters/attachment_presenter.rb +102 -57
- data/lib/presenters/contact_presenter.rb +22 -0
- data/lib/{govspeak/extension → templates}/attachment.html.erb +7 -15
- data/lib/templates/contact.html.erb +2 -2
- data/lib/templates/inline_attachment.html.erb +6 -0
- data/test/govspeak_attachments_image_test.rb +108 -0
- data/test/govspeak_attachments_inline_test.rb +172 -0
- data/test/govspeak_attachments_test.rb +411 -0
- data/test/govspeak_contacts_test.rb +10 -6
- data/test/govspeak_link_test.rb +45 -0
- data/test/govspeak_test.rb +21 -90
- metadata +47 -7
- data/lib/govspeak/extension/inline_attachment.html.erb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 726774ba404422dd313e1afb12bbc3d1c2e036fd
|
4
|
+
data.tar.gz: 4f7e5f0f7b4c9e67c33120050f3021048c13dec7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a144b4353edd665f01109bd1eae1ff569f22ea6133bf564024e973d7df730e9f318d9eb76e76df5917e130b10dbf9897dcbcd75ccfdb816ba291b16e3e9349a0
|
7
|
+
data.tar.gz: 8370760f5a9929f8c33b001d99fc5409900182d815bbae0059c33360d47ef7ccd560ae4b206bdec7940747b73ce9e544edffd10751a7107070b8a9aa49006e8f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 5.0.0
|
2
|
+
* Update Kramdown version to 1.12.0
|
3
|
+
* Add pry-byebug to development dependencies
|
4
|
+
* Ability to run Govspeak as a binary from command line [#87](https://github.com/alphagov/govspeak/pull/87)
|
5
|
+
* Uses hashes the primary interface for options to commands [#89](https://github.com/alphagov/govspeak/pull/89)
|
6
|
+
* Adds the `[embed:attachments:image:%content_id%]` extension [#90](https://github.com/alphagov/govspeak/pull/90)
|
7
|
+
* Renders incorrect usages of embedding content as empty strings rather than outputting markdown [91](https://github.com/alphagov/govspeak/pull/91)
|
8
|
+
|
1
9
|
## 4.0.0
|
2
10
|
|
3
11
|
* Drop support for Ruby 1.9.3
|
data/README.md
CHANGED
@@ -18,6 +18,18 @@ then create a new document
|
|
18
18
|
doc = Govspeak::Document.new "^Test^"
|
19
19
|
puts doc.to_html
|
20
20
|
|
21
|
+
or alternatively, run it from the command line
|
22
|
+
|
23
|
+
$ govspeak "render-me"
|
24
|
+
$ govspeak --file render-me.md
|
25
|
+
$ echo "render-me" | govspeak
|
26
|
+
|
27
|
+
options can be passed in through `--options` as a string of JSON or a file
|
28
|
+
of JSON can be passed in as `--options-file options.json`.
|
29
|
+
|
30
|
+
if installed via bundler prefix commands with bundle exec eg `$ bundle exec govspeak "render-me"`
|
31
|
+
|
32
|
+
|
21
33
|
# Extensions
|
22
34
|
|
23
35
|
In addition to the [standard Markdown syntax](http://daringfireball.net/projects/markdown/syntax "Markdown syntax"), we have added our own extensions.
|
data/bin/govspeak
ADDED
data/lib/govspeak.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'kramdown'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'active_support/core_ext/array'
|
2
4
|
require 'govspeak/header_extractor'
|
3
5
|
require 'govspeak/structured_header_extractor'
|
4
6
|
require 'govspeak/html_validator'
|
@@ -9,6 +11,7 @@ require 'govspeak/post_processor'
|
|
9
11
|
require 'kramdown/parser/kramdown_with_automatic_external_links'
|
10
12
|
require 'htmlentities'
|
11
13
|
require 'presenters/attachment_presenter'
|
14
|
+
require 'presenters/contact_presenter'
|
12
15
|
require 'presenters/h_card_presenter'
|
13
16
|
require 'erb'
|
14
17
|
|
@@ -29,11 +32,12 @@ module Govspeak
|
|
29
32
|
end
|
30
33
|
|
31
34
|
def initialize(source, options = {})
|
35
|
+
options.deep_symbolize_keys!
|
32
36
|
@source = source ? source.dup : ""
|
33
37
|
@images = options.delete(:images) || []
|
34
|
-
@attachments = Array(options.delete(:attachments))
|
35
|
-
@links = Array(options.delete(:links))
|
36
|
-
@contacts = Array(options.delete(:contacts))
|
38
|
+
@attachments = Array.wrap(options.delete(:attachments))
|
39
|
+
@links = Array.wrap(options.delete(:links))
|
40
|
+
@contacts = Array.wrap(options.delete(:contacts))
|
37
41
|
@locale = options.fetch(:locale, "en")
|
38
42
|
@options = {input: PARSER_CLASS_NAME}.merge(options)
|
39
43
|
@options[:entity_output] = :symbolic
|
@@ -185,29 +189,52 @@ module Govspeak
|
|
185
189
|
end
|
186
190
|
end
|
187
191
|
|
188
|
-
extension('attachment', /\[embed:attachments:(
|
189
|
-
attachment = attachments.detect { |a| a
|
192
|
+
extension('attachment', /\[embed:attachments:(?!inline:|image:)\s*(.*?)\s*\]/) do |content_id, body|
|
193
|
+
attachment = attachments.detect { |a| a[:content_id].match(content_id) }
|
190
194
|
next "" unless attachment
|
191
195
|
attachment = AttachmentPresenter.new(attachment)
|
192
|
-
content = File.read('
|
196
|
+
content = File.read(__dir__ + '/templates/attachment.html.erb')
|
193
197
|
ERB.new(content).result(binding)
|
194
198
|
end
|
195
199
|
|
196
|
-
extension('attachment inline', /\[embed:attachments:inline
|
197
|
-
attachment = attachments.detect { |a| a
|
200
|
+
extension('attachment inline', /\[embed:attachments:inline:\s*(.*?)\s*\]/) do |content_id|
|
201
|
+
attachment = attachments.detect { |a| a[:content_id].match(content_id) }
|
198
202
|
next "" unless attachment
|
199
203
|
attachment = AttachmentPresenter.new(attachment)
|
200
|
-
|
201
|
-
|
204
|
+
span_id = attachment.id ? %{ id="attachment_#{attachment.id}"} : ""
|
205
|
+
# new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
|
206
|
+
title = (attachment.title || "").tr("\n", " ")
|
207
|
+
link = attachment.link(title, attachment.url)
|
208
|
+
attributes = attachment.attachment_attributes.empty? ? "" : " (#{attachment.attachment_attributes})"
|
209
|
+
%{<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>}
|
202
210
|
end
|
203
211
|
|
204
|
-
|
212
|
+
extension('attachment image', /\[embed:attachments:image:\s*(.*?)\s*\]/) do |content_id|
|
213
|
+
attachment = attachments.detect { |a| a[:content_id].match(content_id) }
|
214
|
+
next "" unless attachment
|
215
|
+
attachment = AttachmentPresenter.new(attachment)
|
216
|
+
title = (attachment.title || "").tr("\n", " ")
|
217
|
+
render_image(attachment.url, title, nil, attachment.id)
|
218
|
+
end
|
219
|
+
|
220
|
+
# As of version 1.12.0 of Kramdown the block elements (div & figcaption)
|
221
|
+
# inside this html block will have it's < > converted into HTML Entities
|
222
|
+
# when ever this code is used inside block level elements.
|
223
|
+
#
|
224
|
+
# To resolve this we have a post-processing task that will convert this
|
225
|
+
# back into HTML (I know - it's ugly). The way we could resolve this
|
226
|
+
# without ugliness would be to output only inline elements which rules
|
227
|
+
# out div and figcaption
|
228
|
+
#
|
229
|
+
# This issue is not considered a bug by kramdown: https://github.com/gettalong/kramdown/issues/191
|
230
|
+
def render_image(url, alt_text, caption = nil, id = nil)
|
231
|
+
id_attr = id ? %{ id="attachment_#{id}"} : ""
|
205
232
|
lines = []
|
206
|
-
lines <<
|
207
|
-
lines << %Q{
|
208
|
-
lines << %Q{
|
233
|
+
lines << %{<figure#{id_attr} class="image embedded">}
|
234
|
+
lines << %Q{<div class="img"><img src="#{encode(url)}" alt="#{encode(alt_text)}"></div>}
|
235
|
+
lines << %Q{<figcaption>#{caption.strip}</figcaption>} if caption && !caption.strip.empty?
|
209
236
|
lines << '</figure>'
|
210
|
-
lines.join
|
237
|
+
lines.join
|
211
238
|
end
|
212
239
|
|
213
240
|
wrap_with_div('summary', '$!')
|
@@ -272,13 +299,13 @@ module Govspeak
|
|
272
299
|
end
|
273
300
|
end
|
274
301
|
|
275
|
-
extension('embed link', /\[embed:link
|
276
|
-
link = links.detect { |l| l
|
302
|
+
extension('embed link', /\[embed:link:\s*(.*?)\s*\]/) do |content_id|
|
303
|
+
link = links.detect { |l| l[:content_id].match(content_id) }
|
277
304
|
next "" unless link
|
278
|
-
if link
|
279
|
-
%Q{<a href="#{encode(link
|
305
|
+
if link[:url]
|
306
|
+
%Q{<a href="#{encode(link[:url])}">#{link[:title]}</a>}
|
280
307
|
else
|
281
|
-
|
308
|
+
link[:title]
|
282
309
|
end
|
283
310
|
end
|
284
311
|
|
@@ -287,10 +314,11 @@ module Govspeak
|
|
287
314
|
end
|
288
315
|
private :render_hcard_address
|
289
316
|
|
290
|
-
extension('Contact', /\[Contact
|
291
|
-
contact = contacts.detect { |c| c
|
317
|
+
extension('Contact', /\[Contact:\s*(.*?)\s*\]/) do |content_id|
|
318
|
+
contact = contacts.detect { |c| c[:content_id].match(content_id) }
|
292
319
|
next "" unless contact
|
293
|
-
|
320
|
+
contact = ContactPresenter.new(contact)
|
321
|
+
@renderer ||= ERB.new(File.read(__dir__ + '/templates/contact.html.erb'))
|
294
322
|
@renderer.result(binding)
|
295
323
|
end
|
296
324
|
end
|
data/lib/govspeak/cli.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'govspeak/version'
|
2
|
+
require 'govspeak'
|
3
|
+
require 'commander'
|
4
|
+
|
5
|
+
module Govspeak
|
6
|
+
class CLI
|
7
|
+
include Commander::Methods
|
8
|
+
|
9
|
+
def run
|
10
|
+
program(:name, 'Govspeak')
|
11
|
+
program(:version, Govspeak::VERSION)
|
12
|
+
program(:description, "A tool for rendering the GOV.UK dialect of markdown into HTML")
|
13
|
+
default_command(:render)
|
14
|
+
command(:render) do |command|
|
15
|
+
command.syntax = "govspeak render [options] <input>"
|
16
|
+
command.description = "Render Govspeak into HTML, can be sourced from stdin, as an argument or from a file"
|
17
|
+
command.option("--file FILENAME", String, "File to render")
|
18
|
+
command.option("--options JSON", String, "JSON to use as options")
|
19
|
+
command.option("--options-file FILENAME", String, "A file of JSON options")
|
20
|
+
command.action do |args, options|
|
21
|
+
input = get_input($stdin, args, options)
|
22
|
+
raise "Nothing to render. Use --help for assistance" unless input
|
23
|
+
puts Govspeak::Document.new(input, govspeak_options(options)).to_html
|
24
|
+
end
|
25
|
+
end
|
26
|
+
run!
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def get_input(stdin, args, options)
|
32
|
+
return stdin.read unless stdin.tty?
|
33
|
+
return read_file(options.file) if options.file
|
34
|
+
args.empty? ? nil : args.join(" ")
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_file(file_path)
|
38
|
+
path = Pathname.new(file_path).realpath
|
39
|
+
File.read(path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def govspeak_options(command_options)
|
43
|
+
string = if command_options.options_file
|
44
|
+
read_file(command_options.options_file)
|
45
|
+
else
|
46
|
+
command_options.options
|
47
|
+
end
|
48
|
+
string ? JSON.load(string) : {}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -38,5 +38,31 @@ module Govspeak
|
|
38
38
|
el[:class] = "last-child"
|
39
39
|
end
|
40
40
|
end
|
41
|
+
|
42
|
+
# This "fix" here is tied into the rendering of images as one of the
|
43
|
+
# pre-processor tasks. As images can be created inside block level elements
|
44
|
+
# it's possible that their block level elements can be HTML entity escaped
|
45
|
+
# to produce "valid" HTML.
|
46
|
+
#
|
47
|
+
# This sucks for us as we spit the user out HTML elements.
|
48
|
+
#
|
49
|
+
# This fix reverses this, and of course, totally sucks because it's tightly
|
50
|
+
# coupled to the `render_image` code and it really isn't cool to undo HTML
|
51
|
+
# entity encoding.
|
52
|
+
extension("fix image attachment escaping") do |document|
|
53
|
+
document.css("figure.image").map do |el|
|
54
|
+
xml = el.children.to_s
|
55
|
+
next unless xml =~ /<div class="img">|<figcaption>/
|
56
|
+
el.children = xml
|
57
|
+
.gsub(
|
58
|
+
%r{<(div class="img")>(.*?)<(/div)>},
|
59
|
+
"<\\1>\\2<\\3>"
|
60
|
+
)
|
61
|
+
.gsub(
|
62
|
+
%r{<(figcaption)>(.*?)<(/figcaption&)gt;},
|
63
|
+
"<\\1>\\2<\\3>"
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
41
67
|
end
|
42
68
|
end
|
data/lib/govspeak/version.rb
CHANGED
@@ -1,77 +1,80 @@
|
|
1
1
|
require "action_view"
|
2
2
|
require "money"
|
3
|
+
require "htmlentities"
|
3
4
|
|
4
5
|
class AttachmentPresenter
|
5
6
|
attr_reader :attachment
|
6
7
|
include ActionView::Helpers::TagHelper
|
7
8
|
include ActionView::Helpers::NumberHelper
|
8
9
|
include ActionView::Helpers::AssetTagHelper
|
10
|
+
include ActionView::Helpers::TextHelper
|
9
11
|
|
10
12
|
def initialize(attachment)
|
11
13
|
@attachment = attachment
|
12
14
|
end
|
13
15
|
|
14
16
|
def id
|
15
|
-
attachment
|
17
|
+
attachment[:id]
|
16
18
|
end
|
17
19
|
|
18
20
|
def order_url
|
19
|
-
attachment
|
21
|
+
attachment[:order_url]
|
20
22
|
end
|
21
23
|
|
22
24
|
def opendocument?
|
23
|
-
attachment
|
25
|
+
attachment[:opendocument?]
|
24
26
|
end
|
25
27
|
|
26
28
|
def url
|
27
|
-
attachment
|
29
|
+
attachment[:url]
|
28
30
|
end
|
29
31
|
|
30
32
|
def external?
|
31
|
-
attachment
|
33
|
+
attachment[:external?]
|
32
34
|
end
|
33
35
|
|
34
36
|
def price
|
35
|
-
return unless attachment
|
36
|
-
Money.from_amount(attachment
|
37
|
+
return unless attachment[:price]
|
38
|
+
Money.from_amount(attachment[:price], 'GBP').format
|
37
39
|
end
|
38
40
|
|
39
41
|
def accessible?
|
40
|
-
attachment
|
42
|
+
attachment[:accessible?]
|
41
43
|
end
|
42
44
|
|
43
45
|
def thumbnail_link
|
44
46
|
return if hide_thumbnail?
|
45
47
|
return if previewable?
|
46
|
-
link(attachment_thumbnail, url, "aria-hidden
|
48
|
+
link(attachment_thumbnail, url, "aria-hidden" => "true", "class" => attachment_class)
|
47
49
|
end
|
48
50
|
|
49
51
|
def help_block_toggle_id
|
50
|
-
"attachment-#{
|
52
|
+
"attachment-#{id}-accessibility-request"
|
51
53
|
end
|
52
54
|
|
53
55
|
def section_class
|
54
|
-
attachment
|
56
|
+
attachment[:external?] ? "hosted-externally" : "embedded"
|
55
57
|
end
|
56
58
|
|
57
59
|
def mail_to(email_address, name, options = {})
|
58
|
-
|
60
|
+
query_string = options.slice(:subject, :body).map { |k, v| "#{urlencode(k)}=#{urlencode(v)}" }.join("&")
|
61
|
+
"<a href='mailto:#{encode(email_address)}?#{encode(query_string)}'>#{name}</a>"
|
59
62
|
end
|
60
63
|
|
61
64
|
def alternative_format_order_link
|
62
65
|
attachment_info = []
|
63
|
-
attachment_info << " Title: #{
|
64
|
-
attachment_info << " Original format: #{
|
65
|
-
attachment_info << " ISBN: #{attachment
|
66
|
-
attachment_info << " Unique reference: #{attachment
|
67
|
-
attachment_info << " Command paper number: #{attachment
|
68
|
-
if attachment
|
69
|
-
attachment_info << " House of Commons paper number: #{attachment
|
70
|
-
attachment_info << " Parliamentary session: #{attachment
|
66
|
+
attachment_info << " Title: #{title}"
|
67
|
+
attachment_info << " Original format: #{file_extension}" if file_extension.present?
|
68
|
+
attachment_info << " ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
69
|
+
attachment_info << " Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
70
|
+
attachment_info << " Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
71
|
+
if attachment[:hoc_paper_number].present?
|
72
|
+
attachment_info << " House of Commons paper number: #{attachment[:hoc_paper_number]}"
|
73
|
+
attachment_info << " Parliamentary session: #{attachment[:parliamentary_session]}"
|
71
74
|
end
|
72
75
|
|
73
76
|
options = {
|
74
|
-
subject: "Request for '#{
|
77
|
+
subject: "Request for '#{title}' in an alternative format",
|
75
78
|
body: body_for_mail(attachment_info)
|
76
79
|
}
|
77
80
|
|
@@ -80,7 +83,7 @@ class AttachmentPresenter
|
|
80
83
|
|
81
84
|
def body_for_mail(attachment_info)
|
82
85
|
<<-END
|
83
|
-
|
86
|
+
Details of document required:
|
84
87
|
|
85
88
|
#{attachment_info.join("\n")}
|
86
89
|
|
@@ -95,66 +98,93 @@ Please tell us:
|
|
95
98
|
"govuk-feedback@digital.cabinet-office.gov.uk"
|
96
99
|
end
|
97
100
|
|
101
|
+
# FIXME: usage of image_tag will cause these to render at /images/ which seems
|
102
|
+
# very host dependent. I assume this will need links to static urls.
|
98
103
|
def attachment_thumbnail
|
99
|
-
if attachment
|
100
|
-
image_tag(attachment
|
101
|
-
elsif
|
104
|
+
if file_extension == "pdf" && attachment[:thumbnail_url]
|
105
|
+
image_tag(attachment[:thumbnail_url])
|
106
|
+
elsif file_extension == "html"
|
102
107
|
image_tag('pub-cover-html.png')
|
103
|
-
elsif %w{doc docx odt}.include?
|
108
|
+
elsif %w{doc docx odt}.include?(file_extension)
|
104
109
|
image_tag('pub-cover-doc.png')
|
105
|
-
elsif %w{xls xlsx ods csv}.include?
|
110
|
+
elsif %w{xls xlsx ods csv}.include?(file_extension)
|
106
111
|
image_tag('pub-cover-spreadsheet.png')
|
107
112
|
else
|
108
113
|
image_tag('pub-cover.png')
|
109
114
|
end
|
110
115
|
end
|
111
116
|
|
112
|
-
def
|
117
|
+
def reference
|
118
|
+
ref = []
|
119
|
+
if attachment[:isbn].present?
|
120
|
+
ref << "ISBN " + content_tag(:span, attachment[:isbn], class: "isbn")
|
121
|
+
end
|
122
|
+
|
123
|
+
if attachment[:unique_reference].present?
|
124
|
+
ref << content_tag(:span, attachment[:unique_reference], class: "unique_reference")
|
125
|
+
end
|
126
|
+
|
127
|
+
if attachment[:command_paper_number].present?
|
128
|
+
ref << content_tag(:span, attachment[:command_paper_number], class: "command_paper_number")
|
129
|
+
end
|
130
|
+
|
131
|
+
if attachment[:hoc_paper_number].present?
|
132
|
+
ref << content_tag(:span, "HC #{attachment[:hoc_paper_number]}", class: 'house_of_commons_paper_number') + ' ' +
|
133
|
+
content_tag(:span, attachment[:parliamentary_session], class: 'parliamentary_session')
|
134
|
+
end
|
135
|
+
|
136
|
+
ref.join(', ').html_safe
|
137
|
+
end
|
138
|
+
|
139
|
+
# FIXME this has english in it so will cause problems if the locale is not en
|
140
|
+
def references_for_title
|
113
141
|
references = []
|
114
|
-
references << "ISBN: #{attachment
|
115
|
-
references << "Unique reference: #{attachment
|
116
|
-
references << "Command paper number: #{attachment
|
117
|
-
references << "HC: #{attachment
|
142
|
+
references << "ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
143
|
+
references << "Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
144
|
+
references << "Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
145
|
+
references << "HC: #{attachment[:hoc_paper_number]} #{attachment[:parliamentary_session]}" if attachment[:hoc_paper_number].present?
|
118
146
|
prefix = references.size == 1 ? "and its reference" : "and its references"
|
119
147
|
references.any? ? ", #{prefix} (" + references.join(", ") + ")" : ""
|
120
148
|
end
|
121
149
|
|
122
150
|
def references?
|
123
|
-
!attachment
|
151
|
+
!attachment[:isbn].to_s.empty? || !attachment[:unique_reference].to_s.empty? || !attachment[:command_paper_number].to_s.empty? || !attachment[:hoc_paper_number].to_s.empty?
|
124
152
|
end
|
125
153
|
|
126
154
|
def attachment_class
|
127
|
-
attachment
|
155
|
+
attachment[:external?] ? "hosted-externally" : "embedded"
|
128
156
|
end
|
129
157
|
|
130
158
|
def unnumbered_paper?
|
131
|
-
attachment
|
159
|
+
attachment[:unnumbered_command_paper?] || attachment[:unnumbered_hoc_paper?]
|
132
160
|
end
|
133
161
|
|
134
162
|
def unnumbered_command_paper?
|
135
|
-
attachment
|
163
|
+
attachment[:unnumbered_command_paper?]
|
136
164
|
end
|
137
165
|
|
138
166
|
def download_link
|
139
|
-
|
167
|
+
options = {}
|
168
|
+
options[:title] = number_to_human_size(attachment[:file_size]) if attachment[:file_size].present?
|
169
|
+
link("<strong>Download #{file_extension.upcase}</strong>", attachment[:url], options)
|
140
170
|
end
|
141
171
|
|
142
172
|
def attachment_attributes
|
143
173
|
attributes = []
|
144
|
-
if
|
174
|
+
if file_extension == "html"
|
145
175
|
attributes << content_tag(:span, 'HTML', class: 'type')
|
146
|
-
elsif attachment
|
176
|
+
elsif attachment[:external?]
|
147
177
|
attributes << content_tag(:span, url, class: 'url')
|
148
178
|
else
|
149
|
-
attributes << content_tag(:span, humanized_content_type(
|
150
|
-
attributes << content_tag(:span, number_to_human_size(attachment
|
151
|
-
attributes << content_tag(:span, pluralize(attachment
|
179
|
+
attributes << content_tag(:span, humanized_content_type(file_extension), class: 'type') if file_extension
|
180
|
+
attributes << content_tag(:span, number_to_human_size(attachment[:file_size]), class: 'file-size') if attachment[:file_size]
|
181
|
+
attributes << content_tag(:span, pluralize(attachment[:number_of_pages], "page"), class: 'page-length') if attachment[:number_of_pages]
|
152
182
|
end
|
153
183
|
attributes.join(', ').html_safe
|
154
184
|
end
|
155
185
|
|
156
186
|
def preview_url
|
157
|
-
url
|
187
|
+
url + '/preview'
|
158
188
|
end
|
159
189
|
|
160
190
|
MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE = "MS Word Document"
|
@@ -205,37 +235,52 @@ Please tell us:
|
|
205
235
|
end
|
206
236
|
|
207
237
|
def previewable?
|
208
|
-
|
238
|
+
file_extension == "csv"
|
209
239
|
end
|
210
240
|
|
211
241
|
def title
|
212
|
-
attachment
|
242
|
+
attachment[:title]
|
243
|
+
end
|
244
|
+
|
245
|
+
def file_extension
|
246
|
+
# Note: this is a separate parameter rather than being calculated from the
|
247
|
+
# filename because at the time of writing not all apps were using the effects
|
248
|
+
# of this field.
|
249
|
+
attachment[:file_extension]
|
213
250
|
end
|
214
251
|
|
215
252
|
def hide_thumbnail?
|
216
253
|
defined?(hide_thumbnail) && hide_thumbnail
|
217
254
|
end
|
218
255
|
|
219
|
-
def
|
256
|
+
def attachment_details
|
220
257
|
return if previewable?
|
221
|
-
link(
|
258
|
+
link(title, url, title_link_options)
|
222
259
|
end
|
223
260
|
|
224
261
|
def title_link_options
|
225
|
-
title_link_options =
|
226
|
-
title_link_options
|
227
|
-
title_link_options
|
262
|
+
title_link_options = {}
|
263
|
+
title_link_options["rel"] = "external" if attachment[:external?]
|
264
|
+
title_link_options["aria-describedby"] = help_block_id unless attachment[:accessible?]
|
265
|
+
title_link_options
|
228
266
|
end
|
229
267
|
|
230
268
|
def help_block_id
|
231
|
-
"attachment-#{
|
269
|
+
"attachment-#{id}-accessibility-help"
|
232
270
|
end
|
233
271
|
|
234
|
-
def link(body, url, options={})
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
272
|
+
def link(body, url, options = {})
|
273
|
+
options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
|
274
|
+
%{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
|
279
|
+
def encode(text)
|
280
|
+
HTMLEntities.new.encode(text)
|
281
|
+
end
|
282
|
+
|
283
|
+
def urlencode(text)
|
284
|
+
ERB::Util.url_encode(text)
|
240
285
|
end
|
241
286
|
end
|