govspeak 4.0.0 → 5.0.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.
- 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
|