govspeak 6.0.0 → 6.1.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +1 -45
  4. data/lib/govspeak.rb +18 -8
  5. data/lib/govspeak/blockquote_extra_quote_remover.rb +4 -3
  6. data/lib/govspeak/html_sanitizer.rb +1 -1
  7. data/lib/govspeak/post_processor.rb +25 -3
  8. data/lib/govspeak/presenters/attachment_presenter.rb +7 -194
  9. data/lib/govspeak/version.rb +1 -1
  10. data/locales/ar.yml +0 -17
  11. data/locales/be.yml +0 -17
  12. data/locales/bg.yml +0 -19
  13. data/locales/cs.yml +0 -19
  14. data/locales/cy.yml +0 -18
  15. data/locales/de.yml +0 -18
  16. data/locales/el.yml +0 -19
  17. data/locales/en.yml +0 -20
  18. data/locales/es-419.yml +0 -18
  19. data/locales/es.yml +0 -18
  20. data/locales/et.yml +0 -19
  21. data/locales/fa.yml +0 -17
  22. data/locales/fr.yml +0 -18
  23. data/locales/he.yml +0 -18
  24. data/locales/hi.yml +0 -18
  25. data/locales/hu.yml +0 -18
  26. data/locales/hy.yml +0 -18
  27. data/locales/id.yml +0 -17
  28. data/locales/it.yml +0 -18
  29. data/locales/ja.yml +0 -16
  30. data/locales/ko.yml +0 -16
  31. data/locales/lt.yml +0 -17
  32. data/locales/lv.yml +0 -17
  33. data/locales/pl.yml +0 -19
  34. data/locales/ps.yml +0 -17
  35. data/locales/pt.yml +0 -17
  36. data/locales/ro.yml +0 -19
  37. data/locales/ru.yml +0 -16
  38. data/locales/si.yml +0 -17
  39. data/locales/sr.yml +0 -18
  40. data/locales/ta.yml +0 -19
  41. data/locales/th.yml +0 -16
  42. data/locales/tr.yml +0 -17
  43. data/locales/uk.yml +0 -17
  44. data/locales/ur.yml +0 -18
  45. data/locales/uz.yml +0 -17
  46. data/locales/vi.yml +0 -17
  47. data/locales/zh-hk.yml +0 -15
  48. data/locales/zh-tw.yml +0 -15
  49. data/locales/zh.yml +0 -15
  50. data/test/blockquote_extra_quote_remover_test.rb +7 -0
  51. data/test/govspeak_attachment_link_test.rb +25 -0
  52. data/test/govspeak_attachment_test.rb +40 -0
  53. metadata +33 -35
  54. data/lib/templates/attachment.html.erb +0 -57
  55. data/locales/dr.yml +0 -20
  56. data/locales/so.yml +0 -22
  57. data/locales/sq.yml +0 -21
  58. data/test/govspeak_attachments_test.rb +0 -358
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93b2022644e3af2c929faf57f33c9fe70680977e599bde24d59c71ee20402713
4
- data.tar.gz: 7dec8938eedb2183514c54665dd9609f130ac535fbb336739f0f8b6e3d528bc3
3
+ metadata.gz: ec0c2e0694235f631985feeea77f20f07f8ce6ccaf55a8317a83b42583a6bcd2
4
+ data.tar.gz: f98e90a503d00b4dd7c92c9b4dd9e1ff4e3a14494787a344f3722cd788515294
5
5
  SHA512:
6
- metadata.gz: 7b96f54ac8cfdf3e0595cb2de3bc205df86c7efc9869c4e9d06f22623067f4e114d878e9f31c72817d76657b9d759e0b3344ae87724db8394a5a79a727765407
7
- data.tar.gz: 9fc03735199e9fe6016ffe1196e57eac617a744c7aaa3421fc1a57a4ba53190c3dc85c5dda7f76b202aaf29c7c5da51f47ed0fcf71ff43a5b504097bcf8b6ebb
6
+ metadata.gz: b45e92bd8d25ef8a0674de0aba0ac4785589a3af588bf07893b567e09792b13deb15101ba85aef05c45b4429982add8ff52669abfa8b273a9ce29d51591c908b
7
+ data.tar.gz: b193767c7dd265bf61ac851cdc2b0caafd249f63057f5b2008e9dea991ae8d79166fa86169305cf099d3a3ddf1fbe0f1c256f02216d27ae95d2ad2f7a2f17d1e
@@ -1,3 +1,11 @@
1
+ ## 6.1.0
2
+
3
+ * Remove `[embed:attachments:content-id]` this isn't used by any apps and has never worked
4
+ * Add dependency on govuk_publishing_components
5
+ * Add new `AttachementLink:attachment-id` extension and mark as experimental
6
+ * Add new `Attachement:attachment-id` extension and mark as experimental
7
+ * Blockquote quote remover is now more forgiving to spaces before or after quote characters
8
+
1
9
  ## 6.0.0
2
10
 
3
11
  * BREAKING CHANGE: Input is sanitized by default, to use unsafe HTML initialize with a sanitize option of false
data/README.md CHANGED
@@ -352,53 +352,9 @@ Embedded content allows authors to reference a supporting item of a document by
352
352
  referencing an id. The details of this content is passed to the publishing
353
353
  application to govspeak at the time of rendering.
354
354
 
355
- ### Attachments
356
-
357
- To create an attachment callout
358
-
359
- [embed:attachment:2b4d92f3-f8cd-4284-aaaa-25b3a640d26c]
360
-
361
- with options provided
362
-
363
- {
364
- attachments: [
365
- {
366
- id: 123,
367
- content_id: "2b4d92f3-f8cd-4284-aaaa-25b3a640d26c",
368
- title: "Attachment Title",
369
- url: "http://example.com/test.pdf",
370
- order_url: "http://example.com/order",
371
- price: 12.3,
372
- isbn: "isbn-123",
373
- attachment?: true,
374
- }
375
- ]
376
- }
377
-
378
- will output an attachment box
379
-
380
- ```html
381
- <section class="attachment embedded">
382
- <div class="attachment-thumb">
383
- <a href="http://example.com/test.pdf" aria-hidden="true" class="embedded"><img src="/images/pub-cover.png" alt="Pub cover"></a>
384
- </div>
385
- <div class="attachment-details">
386
- <h2 class="title">
387
- <a href="http://example.com/test.pdf" aria-describedby="attachment-123-accessibility-help">Attachment Title</a>
388
- </h2>
389
- <p class="metadata">
390
- <span class="references">Ref: ISBN <span class="isbn">isbn-123</span></span>
391
- </p>
392
- <p>
393
- <a href="http://example.com/order" class="order_url" title="Order a copy of the publication">Order a copy</a>(<span class="price">£12.30</span>)
394
- </p>
395
- </div>
396
- </section>
397
- ```
398
-
399
355
  ### Inline Attachment
400
356
 
401
- Attachments can be linked to inline as well
357
+ Attachments can be linked to inline
402
358
 
403
359
  Details referenced in [embed:attachments:inline:34f6dda0-21b1-4e78-8120-3ff4dcea522d]
404
360
 
@@ -5,6 +5,7 @@ require 'htmlentities'
5
5
  require 'kramdown'
6
6
  require 'kramdown/parser/kramdown_with_automatic_external_links'
7
7
  require 'rinku'
8
+ require 'govuk_publishing_components'
8
9
  require 'govspeak/header_extractor'
9
10
  require 'govspeak/structured_header_extractor'
10
11
  require 'govspeak/html_validator'
@@ -217,18 +218,12 @@ module Govspeak
217
218
  render_image(ImagePresenter.new(image))
218
219
  end
219
220
 
220
- extension('attachment', /\[embed:attachments:(?!inline:|image:)\s*(.*?)\s*\]/) do |content_id|
221
- # not treating this as a self closing tag seems to avoid some oddities
222
- # such as an extra new line being inserted when explicitly closed or
223
- # swallowing subsequent elements when not closed
224
- %{<govspeak-embed-attachment content-id="#{content_id}"></govspeak-embed-attachment>}
225
- end
226
-
227
- extension('attachment inline', /\[embed:attachments:inline:\s*(.*?)\s*\]/) do |content_id|
221
+ extension('embed attachment inline', /\[embed:attachments:inline:\s*(.*?)\s*\]/) do |content_id|
228
222
  attachment = attachments.detect { |a| a[:content_id] == content_id }
229
223
  next "" unless attachment
230
224
 
231
225
  attachment = AttachmentPresenter.new(attachment)
226
+
232
227
  span_id = attachment.id ? %{ id="attachment_#{attachment.id}"} : ""
233
228
  # new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
234
229
  title = (attachment.title || "").tr("\n", " ")
@@ -354,6 +349,21 @@ module Govspeak
354
349
  render_image(ImagePresenter.new(image))
355
350
  end
356
351
 
352
+ # This is an alternative syntax for embedding attachments using a readable id (expected
353
+ # to be a unique variation of a filename). This syntax is being used by
354
+ # Content Publisher and should be considered experimental as it is likely
355
+ # to be iterated in the short term.
356
+ extension('Attachment', /#{NEW_PARAGRAPH_LOOKBEHIND}\[Attachment:\s*(.*?)\s*\]/) do |attachment_id|
357
+ %{<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>}
358
+ end
359
+
360
+ # This is an alternative syntax for embedding attachments as links. This
361
+ # syntax is being used by Content Publisher and should be considered
362
+ # experimental
363
+ extension('AttachmentLink', /\[AttachmentLink:\s*(.*?)\s*\]/) do |attachment_id|
364
+ %{<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>}
365
+ end
366
+
357
367
  private
358
368
 
359
369
  def kramdown_doc
@@ -1,7 +1,7 @@
1
1
  module Govspeak
2
2
  module BlockquoteExtraQuoteRemover
3
- QUOTE = '"\u201C\u201D\u201E\u201F\u2033\u2036'.freeze
4
- LINE_BREAK = '\r\n?|\n'.freeze
3
+ QUOTES = '["\u201C\u201D\u201E\u201F\u2033\u2036]+'.freeze
4
+ WHITESPACE = '[^\S\r\n]*'.freeze
5
5
 
6
6
  # used to remove quotes from a markdown blockquote, as these will be inserted
7
7
  # as part of the rendering
@@ -14,7 +14,8 @@ module Govspeak
14
14
  def self.remove(source)
15
15
  return if source.nil?
16
16
 
17
- source.gsub(/^>[ \t]*[#{QUOTE}]*([^ \t\n].+?)[#{QUOTE}]*[ \t]*(#{LINE_BREAK}?)$/, '> \1\2')
17
+ source.gsub(/^>#{WHITESPACE}#{QUOTES}#{WHITESPACE}(.+?)$/, '> \1') # prefixed with a quote
18
+ .gsub(/^>(.+?)#{WHITESPACE}#{QUOTES}#{WHITESPACE}(\r?)$/, '>\1\2') # suffixed with a quote
18
19
  end
19
20
  end
20
21
  end
@@ -60,7 +60,7 @@ class Govspeak::HtmlSanitizer
60
60
  def sanitize_config
61
61
  Sanitize::Config.merge(
62
62
  Sanitize::Config::RELAXED,
63
- elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment],
63
+ elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment govspeak-embed-attachment-link],
64
64
  attributes: {
65
65
  :all => Sanitize::Config::RELAXED[:attributes][:all] + ["role", "aria-label"],
66
66
  "a" => Sanitize::Config::RELAXED[:attributes]["a"] + button_sanitize_config,
@@ -51,14 +51,36 @@ module Govspeak
51
51
 
52
52
  extension("embed attachment HTML") do |document|
53
53
  document.css("govspeak-embed-attachment").map do |el|
54
- attachment = govspeak_document.attachments.detect { |a| a[:content_id] == el["content-id"] }
54
+ attachment = govspeak_document.attachments.detect { |a| a[:id] == el["id"] }
55
+
56
+ unless attachment
57
+ el.remove
58
+ next
59
+ end
60
+
61
+ attachment_html = GovukPublishingComponents.render(
62
+ "govuk_publishing_components/components/attachment",
63
+ attachment: attachment,
64
+ locale: govspeak_document.locale
65
+ )
66
+ el.swap(attachment_html)
67
+ end
68
+ end
69
+
70
+ extension("embed attachment link HTML") do |document|
71
+ document.css("govspeak-embed-attachment-link").map do |el|
72
+ attachment = govspeak_document.attachments.detect { |a| a[:id] == el["id"] }
73
+
55
74
  unless attachment
56
75
  el.remove
57
76
  next
58
77
  end
59
78
 
60
- renderer = TemplateRenderer.new('attachment.html.erb', govspeak_document.locale)
61
- attachment_html = renderer.render(attachment: AttachmentPresenter.new(attachment))
79
+ attachment_html = GovukPublishingComponents.render(
80
+ "govuk_publishing_components/components/attachment_link",
81
+ attachment: attachment,
82
+ locale: govspeak_document.locale
83
+ )
62
84
  el.swap(attachment_html)
63
85
  end
64
86
  end
@@ -1,15 +1,11 @@
1
1
  require "action_view"
2
- require "money"
3
2
  require "htmlentities"
4
3
 
5
- Money.locale_backend = :currency
6
-
7
4
  module Govspeak
8
5
  class AttachmentPresenter
9
6
  attr_reader :attachment
10
7
  include ActionView::Helpers::TagHelper
11
8
  include ActionView::Helpers::NumberHelper
12
- include ActionView::Helpers::AssetTagHelper
13
9
  include ActionView::Helpers::TextHelper
14
10
 
15
11
  def initialize(attachment)
@@ -20,158 +16,19 @@ module Govspeak
20
16
  attachment[:id]
21
17
  end
22
18
 
23
- def order_url
24
- attachment[:order_url]
25
- end
26
-
27
- def opendocument?
28
- attachment[:opendocument?]
29
- end
30
-
31
19
  def url
32
20
  attachment[:url]
33
21
  end
34
22
 
35
- def external?
36
- attachment[:external?]
37
- end
38
-
39
- def price
40
- return unless attachment[:price]
41
-
42
- Money.from_amount(attachment[:price], 'GBP').format
43
- end
44
-
45
- def accessible?
46
- attachment[:accessible?]
47
- end
48
-
49
- def thumbnail_link
50
- return if hide_thumbnail?
51
- return if previewable?
52
-
53
- link(attachment_thumbnail, url, "aria-hidden" => "true", "class" => attachment_class)
54
- end
55
-
56
- def help_block_toggle_id
57
- "attachment-#{id}-accessibility-request"
58
- end
59
-
60
- def section_class
61
- attachment[:external?] ? "hosted-externally" : "embedded"
62
- end
63
-
64
- def mail_to(email_address, name, options = {})
65
- query_string = options.slice(:subject, :body).map { |k, v| "#{urlencode(k)}=#{urlencode(v)}" }.join("&")
66
- "<a href='mailto:#{encode(email_address)}?#{encode(query_string)}'>#{name}</a>"
67
- end
68
-
69
- def alternative_format_order_link
70
- attachment_info = []
71
- attachment_info << " Title: #{title}"
72
- attachment_info << " Original format: #{file_extension}" if file_extension.present?
73
- attachment_info << " ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
74
- attachment_info << " Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
75
- attachment_info << " Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
76
- if attachment[:hoc_paper_number].present?
77
- attachment_info << " House of Commons paper number: #{attachment[:hoc_paper_number]}"
78
- attachment_info << " Parliamentary session: #{attachment[:parliamentary_session]}"
79
- end
80
-
81
- options = {
82
- subject: "Request for '#{title}' in an alternative format",
83
- body: body_for_mail(attachment_info)
84
- }
85
-
86
- mail_to(alternative_format_contact_email, alternative_format_contact_email, options)
87
- end
88
-
89
- def body_for_mail(attachment_info)
90
- <<~TEXT
91
- Details of document required:
92
-
93
- #{attachment_info.join("\n")}
94
-
95
- Please tell us:
96
-
97
- 1. What makes this format unsuitable for you?
98
- 2. What format you would prefer?
99
- TEXT
100
- end
101
-
102
- def alternative_format_contact_email
103
- "govuk-feedback@digital.cabinet-office.gov.uk"
104
- end
105
-
106
- # FIXME: usage of image_tag will cause these to render at /images/ which seems
107
- # very host dependent. I assume this will need links to static urls.
108
- def attachment_thumbnail
109
- if file_extension == "pdf" && attachment[:thumbnail_url]
110
- image_tag(attachment[:thumbnail_url])
111
- elsif file_extension == "html"
112
- image_tag('pub-cover-html.png')
113
- elsif %w{doc docx odt}.include?(file_extension)
114
- image_tag('pub-cover-doc.png')
115
- elsif %w{xls xlsx ods csv}.include?(file_extension)
116
- image_tag('pub-cover-spreadsheet.png')
117
- else
118
- image_tag('pub-cover.png')
119
- end
120
- end
121
-
122
- def reference
123
- ref = []
124
- if attachment[:isbn].present?
125
- ref << "ISBN " + content_tag(:span, attachment[:isbn], class: "isbn")
126
- end
127
-
128
- if attachment[:unique_reference].present?
129
- ref << content_tag(:span, attachment[:unique_reference], class: "unique_reference")
130
- end
131
-
132
- if attachment[:command_paper_number].present?
133
- ref << content_tag(:span, attachment[:command_paper_number], class: "command_paper_number")
134
- end
135
-
136
- if attachment[:hoc_paper_number].present?
137
- ref << content_tag(:span, "HC #{attachment[:hoc_paper_number]}", class: 'house_of_commons_paper_number') + ' ' +
138
- content_tag(:span, attachment[:parliamentary_session], class: 'parliamentary_session')
139
- end
140
-
141
- ref.join(', ').html_safe
142
- end
143
-
144
- # FIXME this has english in it so will cause problems if the locale is not en
145
- def references_for_title
146
- references = []
147
- references << "ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
148
- references << "Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
149
- references << "Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
150
- references << "HC: #{attachment[:hoc_paper_number]} #{attachment[:parliamentary_session]}" if attachment[:hoc_paper_number].present?
151
- prefix = references.size == 1 ? "and its reference" : "and its references"
152
- references.any? ? ", #{prefix} (" + references.join(", ") + ")" : ""
153
- end
154
-
155
- def references?
156
- !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?
157
- end
158
-
159
- def attachment_class
160
- attachment[:external?] ? "hosted-externally" : "embedded"
161
- end
162
-
163
- def unnumbered_paper?
164
- attachment[:unnumbered_command_paper?] || attachment[:unnumbered_hoc_paper?]
165
- end
166
-
167
- def unnumbered_command_paper?
168
- attachment[:unnumbered_command_paper?]
23
+ def title
24
+ attachment[:title]
169
25
  end
170
26
 
171
- def download_link
172
- options = {}
173
- options[:title] = number_to_human_size(attachment[:file_size]) if attachment[:file_size].present?
174
- link("<strong>Download #{file_extension.upcase}</strong>", attachment[:url], options)
27
+ def file_extension
28
+ # Note: this is a separate parameter rather than being calculated from the
29
+ # filename because at the time of writing not all apps were using the effects
30
+ # of this field.
31
+ attachment[:file_extension]
175
32
  end
176
33
 
177
34
  def attachment_attributes
@@ -188,10 +45,6 @@ module Govspeak
188
45
  attributes.join(', ').html_safe
189
46
  end
190
47
 
191
- def preview_url
192
- url + '/preview'
193
- end
194
-
195
48
  MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE = "MS Word Document".freeze
196
49
  MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE = "MS Excel Spreadsheet".freeze
197
50
  MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE = "MS Powerpoint Presentation".freeze
@@ -239,42 +92,6 @@ module Govspeak
239
92
  file_extension_vs_humanized_content_type.fetch(file_extension.to_s.downcase, '')
240
93
  end
241
94
 
242
- def previewable?
243
- file_extension == "csv"
244
- end
245
-
246
- def title
247
- attachment[:title]
248
- end
249
-
250
- def file_extension
251
- # Note: this is a separate parameter rather than being calculated from the
252
- # filename because at the time of writing not all apps were using the effects
253
- # of this field.
254
- attachment[:file_extension]
255
- end
256
-
257
- def hide_thumbnail?
258
- defined?(hide_thumbnail) && hide_thumbnail
259
- end
260
-
261
- def attachment_details
262
- return if previewable?
263
-
264
- link(title, url, title_link_options)
265
- end
266
-
267
- def title_link_options
268
- title_link_options = {}
269
- title_link_options["rel"] = "external" if attachment[:external?]
270
- title_link_options["aria-describedby"] = help_block_id unless attachment[:accessible?]
271
- title_link_options
272
- end
273
-
274
- def help_block_id
275
- "attachment-#{id}-accessibility-help"
276
- end
277
-
278
95
  def link(body, url, options = {})
279
96
  options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
280
97
  %{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
@@ -285,9 +102,5 @@ module Govspeak
285
102
  def encode(text)
286
103
  HTMLEntities.new.encode(text)
287
104
  end
288
-
289
- def urlencode(text)
290
- ERB::Util.url_encode(text)
291
- end
292
105
  end
293
106
  end
@@ -1,3 +1,3 @@
1
1
  module Govspeak
2
- VERSION = "6.0.0".freeze
2
+ VERSION = "6.1.0".freeze
3
3
  end