govspeak 6.5.4 → 6.5.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a09b3928e9718aa64cd781681dbc8ac51d8534ddc27b26f54e8416b21f60e501
4
- data.tar.gz: f8b6da3c1bf3c3b4c7792263853837886b42f7dc6abe6346d81289695ea7986d
3
+ metadata.gz: 948aced50c3d3842255ea4206a651229de59b2beef42e0c50e55e204354d9b5f
4
+ data.tar.gz: cc55abe4b54b112a3aa1cb350a94270b11b9f0c11a5ca71479f55bb0efbf657d
5
5
  SHA512:
6
- metadata.gz: 9de09348513cfd10e76a9960bfe8012213a99447244cf9d89a2e3da8cb18f93b28e8b63dd63304de06c51a6e3b9e82bc5b1f2de43ff531dfb23f4832d1a18e0b
7
- data.tar.gz: 0b464f824b1ff7f8ee77619d2dd1195a22c8777b79b675d9e7fbb1b88011075552f496b294e26d9b65908f2a26031de30ff93c1a12ba3a9743786a4219cfb2de
6
+ metadata.gz: 1e0c1b0d6ca1fe4999e4135536328ecdc60bd34f368d986a808cee6de687f58198a080c19beffd47df6d80130edd2010eb1a09ccd840ea8adb9375c0b747e533
7
+ data.tar.gz: e47aeeabecc4ffccff7342d1a1ad2e1ddd6cd8aabf5850f740fa3bf5ecdd9395bbded84222d55a5c8998748d7491a649793c550ab49564cd098486623684b275
@@ -1,3 +1,23 @@
1
+ ## 6.5.9
2
+
3
+ * Adjust footnote markup to accommodate multiple references (PR#198)
4
+
5
+ ## 6.5.8
6
+
7
+ * Customise footnote markup for accessibility (PR#192)
8
+
9
+ ## 6.5.7
10
+
11
+ * Update GOV.UK Publishing components to version to 23.0.0 or greater
12
+
13
+ ## 6.5.6
14
+
15
+ * Update Kramdown version to 2.3.0 or greater
16
+
17
+ ## 6.5.5
18
+
19
+ * Prevent links in table headers being stripped (PR#187)
20
+
1
21
  ## 6.5.4
2
22
 
3
23
  * Require Sanitize to be at least 5.2.1 due to https://nvd.nist.gov/vuln/detail/CVE-2020-4054
data/Rakefile CHANGED
@@ -1,15 +1,18 @@
1
1
  require "rake"
2
2
  require "rake/testtask"
3
+ require "rubocop/rake_task"
3
4
  require "bundler"
4
5
 
5
6
  Bundler::GemHelper.install_tasks
6
7
 
8
+ RuboCop::RakeTask.new
9
+
7
10
  desc "Run basic tests"
8
- Rake::TestTask.new("test") { |t|
11
+ Rake::TestTask.new("test") do |t|
9
12
  t.libs << "test"
10
13
  t.pattern = "test/*_test.rb"
11
14
  t.verbose = true
12
15
  t.warning = true
13
- }
16
+ end
14
17
 
15
- task default: [:test]
18
+ task default: %i[test rubocop]
@@ -57,7 +57,9 @@ module Govspeak
57
57
  @links = Array.wrap(options.delete(:links))
58
58
  @contacts = Array.wrap(options.delete(:contacts))
59
59
  @locale = options.fetch(:locale, "en")
60
- @options = { input: PARSER_CLASS_NAME, sanitize: true }.merge(options)
60
+ @options = { input: PARSER_CLASS_NAME,
61
+ sanitize: true,
62
+ syntax_highlighter: nil }.merge(options)
61
63
  @options[:entity_output] = :symbolic
62
64
  end
63
65
 
@@ -108,9 +110,9 @@ module Govspeak
108
110
  source = Govspeak::BlockquoteExtraQuoteRemover.remove(source)
109
111
  source = remove_forbidden_characters(source)
110
112
  self.class.extensions.each do |_, regexp, block|
111
- source.gsub!(regexp) {
113
+ source.gsub!(regexp) do
112
114
  instance_exec(*Regexp.last_match.captures, &block)
113
- }
115
+ end
114
116
  end
115
117
  source
116
118
  end
@@ -127,20 +129,20 @@ module Govspeak
127
129
  end
128
130
 
129
131
  def self.surrounded_by(open, close = nil)
130
- open = Regexp::escape(open)
132
+ open = Regexp.escape(open)
131
133
  if close
132
- close = Regexp::escape(close)
133
- %r+(?:\r|\n|^)#{open}(.*?)#{close} *(\r|\n|$)?+m
134
+ close = Regexp.escape(close)
135
+ %r{(?:\r|\n|^)#{open}(.*?)#{close} *(\r|\n|$)?}m
134
136
  else
135
- %r+(?:\r|\n|^)#{open}(.*?)#{open}? *(\r|\n|$)+m
137
+ %r{(?:\r|\n|^)#{open}(.*?)#{open}? *(\r|\n|$)}m
136
138
  end
137
139
  end
138
140
 
139
141
  def self.wrap_with_div(class_name, character, parser = Kramdown::Document)
140
- extension(class_name, surrounded_by(character)) { |body|
142
+ extension(class_name, surrounded_by(character)) do |body|
141
143
  content = parser ? parser.new("#{body.strip}\n").to_html : body.strip
142
- %{\n<div class="#{class_name}">\n#{content}</div>\n}
143
- }
144
+ %(\n<div class="#{class_name}">\n#{content}</div>\n)
145
+ end
144
146
  end
145
147
 
146
148
  def insert_strong_inside_p(body, parser = Govspeak::Document)
@@ -160,7 +162,7 @@ module Govspeak
160
162
  \s* # any whitespace between opening bracket and link
161
163
  {\/button} # match ending bracket
162
164
  (?:\r|\n|$) # non-capturing match to make sure end of line and linebreak
163
- }x) { |attributes, text, href|
165
+ }x) do |attributes, text, href|
164
166
  button_classes = "govuk-button"
165
167
  /cross-domain-tracking:(?<cross_domain_tracking>.[^\s*]+)/ =~ attributes
166
168
  data_attribute = ""
@@ -173,36 +175,36 @@ module Govspeak
173
175
  text = text.strip
174
176
  href = href.strip
175
177
 
176
- %{\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n}
177
- }
178
+ %(\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n)
179
+ end
178
180
 
179
- extension("highlight-answer") { |body|
180
- %{\n\n<div class="highlight-answer">
181
- #{Govspeak::Document.new(body.strip).to_html}</div>\n}
182
- }
181
+ extension("highlight-answer") do |body|
182
+ %(\n\n<div class="highlight-answer">
183
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
184
+ end
183
185
 
184
- extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) { |body|
185
- %{\n\n<aside class="stat-headline">
186
- #{Govspeak::Document.new(body.strip).to_html}</aside>\n}
187
- }
186
+ extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) do |body|
187
+ %(\n\n<aside class="stat-headline">
188
+ #{Govspeak::Document.new(body.strip).to_html}</aside>\n)
189
+ end
188
190
 
189
191
  # FIXME: these surrounded_by arguments look dodgy
190
- extension("external", surrounded_by("x[", ")x")) { |body|
192
+ extension("external", surrounded_by("x[", ")x")) do |body|
191
193
  Kramdown::Document.new("[#{body.strip}){:rel='external'}").to_html
192
- }
194
+ end
193
195
 
194
- extension("informational", surrounded_by("^")) { |body|
195
- %{\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
196
- #{Govspeak::Document.new(body.strip).to_html}</div>\n}
197
- }
196
+ extension("informational", surrounded_by("^")) do |body|
197
+ %(\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
198
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
199
+ end
198
200
 
199
- extension("important", surrounded_by("@")) { |body|
200
- %{\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n}
201
- }
201
+ extension("important", surrounded_by("@")) do |body|
202
+ %(\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n)
203
+ end
202
204
 
203
- extension("helpful", surrounded_by("%")) { |body|
204
- %{\n\n<div role="note" aria-label="Warning" class="application-notice help-notice">\n#{Govspeak::Document.new(body.strip).to_html}</div>\n}
205
- }
205
+ extension("helpful", surrounded_by("%")) do |body|
206
+ %(\n\n<div role="note" aria-label="Warning" class="application-notice help-notice">\n#{Govspeak::Document.new(body.strip).to_html}</div>\n)
207
+ end
206
208
 
207
209
  extension("barchart", /{barchart(.*?)}/) do |captures|
208
210
  stacked = ".mc-stacked" if captures.include? "stacked"
@@ -210,13 +212,13 @@ module Govspeak
210
212
  negative = ".mc-negative" if captures.include? "negative"
211
213
 
212
214
  [
213
- "{:",
214
- ".js-barchart-table",
215
- stacked,
216
- compact,
217
- negative,
218
- ".mc-auto-outdent",
219
- "}",
215
+ "{:",
216
+ ".js-barchart-table",
217
+ stacked,
218
+ compact,
219
+ negative,
220
+ ".mc-auto-outdent",
221
+ "}",
220
222
  ].join(" ")
221
223
  end
222
224
 
@@ -234,12 +236,12 @@ module Govspeak
234
236
 
235
237
  attachment = AttachmentPresenter.new(attachment)
236
238
 
237
- span_id = attachment.id ? %{ id="attachment_#{attachment.id}"} : ""
239
+ span_id = attachment.id ? %( id="attachment_#{attachment.id}") : ""
238
240
  # new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
239
241
  title = (attachment.title || "").tr("\n", " ")
240
242
  link = attachment.link(title, attachment.url)
241
243
  attributes = attachment.attachment_attributes.empty? ? "" : " (#{attachment.attachment_attributes})"
242
- %{<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>}
244
+ %(<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>)
243
245
  end
244
246
 
245
247
  # DEPRECATED: use 'Image:image-id' instead
@@ -261,10 +263,10 @@ module Govspeak
261
263
  #
262
264
  # This issue is not considered a bug by kramdown: https://github.com/gettalong/kramdown/issues/191
263
265
  def render_image(image)
264
- id_attr = image.id ? %{ id="attachment_#{image.id}"} : ""
266
+ id_attr = image.id ? %( id="attachment_#{image.id}") : ""
265
267
  lines = []
266
- lines << %{<figure#{id_attr} class="image embedded">}
267
- lines << %{<div class="img"><img src="#{encode(image.url)}" alt="#{encode(image.alt_text)}"></div>}
268
+ lines << %(<figure#{id_attr} class="image embedded">)
269
+ lines << %(<div class="img"><img src="#{encode(image.url)}" alt="#{encode(image.alt_text)}"></div>)
268
270
  lines << image.figcaption_html if image.figcaption?
269
271
  lines << "</figure>"
270
272
  lines.join
@@ -279,9 +281,9 @@ module Govspeak
279
281
  wrap_with_div("example", "$E", Govspeak::Document)
280
282
  wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
281
283
 
282
- extension("address", surrounded_by("$A")) { |body|
283
- %{\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n}
284
- }
284
+ extension("address", surrounded_by("$A")) do |body|
285
+ %(\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n)
286
+ end
285
287
 
286
288
  extension("legislative list", /#{NEW_PARAGRAPH_LOOKBEHIND}\$LegislativeList\s*$(.*?)\$EndLegislativeList/m) do |body|
287
289
  Govspeak::KramdownOverrides.with_kramdown_ordered_lists_disabled do
@@ -295,9 +297,9 @@ module Govspeak
295
297
 
296
298
  extension("numbered list", /^[ \t]*((s\d+\.\s.*(?:\n|$))+)/) do |body|
297
299
  body.gsub!(/s(\d+)\.\s(.*)(?:\n|$)/) do
298
- "<li>#{Govspeak::Document.new($2.strip).to_html}</li>\n"
300
+ "<li>#{Govspeak::Document.new(Regexp.last_match(2).strip).to_html}</li>\n"
299
301
  end
300
- %{<ol class="steps">\n#{body}</ol>}
302
+ %(<ol class="steps">\n#{body}</ol>)
301
303
  end
302
304
 
303
305
  def self.devolved_options
@@ -362,13 +364,13 @@ module Govspeak
362
364
  extension("Attachment", /#{NEW_PARAGRAPH_LOOKBEHIND}\[Attachment:\s*(.*?)\s*\]/) do |attachment_id|
363
365
  next "" if attachments.none? { |a| a[:id] == attachment_id }
364
366
 
365
- %{<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>}
367
+ %(<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>)
366
368
  end
367
369
 
368
370
  extension("AttachmentLink", /\[AttachmentLink:\s*(.*?)\s*\]/) do |attachment_id|
369
371
  next "" if attachments.none? { |a| a[:id] == attachment_id }
370
372
 
371
- %{<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>}
373
+ %(<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>)
372
374
  end
373
375
 
374
376
  private
@@ -54,12 +54,12 @@ class Govspeak::HtmlSanitizer
54
54
  elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment govspeak-embed-attachment-link svg path],
55
55
  attributes: {
56
56
  :all => Sanitize::Config::RELAXED[:attributes][:all] + %w[role aria-label],
57
- "a" => Sanitize::Config::RELAXED[:attributes]["a"] + [:data],
57
+ "a" => Sanitize::Config::RELAXED[:attributes]["a"] + [:data],
58
58
  "svg" => Sanitize::Config::RELAXED[:attributes][:all] + %w[xmlns width height viewbox focusable],
59
59
  "path" => Sanitize::Config::RELAXED[:attributes][:all] + %w[fill d],
60
60
  "div" => [:data],
61
- "th" => Sanitize::Config::RELAXED[:attributes]["th"] + %w[style],
62
- "td" => Sanitize::Config::RELAXED[:attributes]["td"] + %w[style],
61
+ "th" => Sanitize::Config::RELAXED[:attributes]["th"] + %w[style],
62
+ "td" => Sanitize::Config::RELAXED[:attributes]["td"] + %w[style],
63
63
  "govspeak-embed-attachment" => %w[content-id],
64
64
  },
65
65
  )
@@ -1,9 +1,9 @@
1
1
  module Govspeak
2
2
  module KramdownOverrides
3
- # This depends on two internal parts of Kramdown.
3
+ # This depends on two internal parts of Kramdown.
4
4
  # 1. Parser registry (kramdown/parser/kramdown.rb#define_parser)
5
5
  # 2. Kramdown list regexes (kramdown/parser/kramdown/list.rb)
6
- # Updating the Kramdown gem therefore also means updating this file to to
6
+ # Updating the Kramdown gem therefore also means updating this file to to
7
7
  # match Kramdown's internals.
8
8
 
9
9
  def self.with_kramdown_ordered_lists_disabled
@@ -14,9 +14,9 @@ module Govspeak
14
14
  attr_reader :document, :website_root
15
15
 
16
16
  def extract_links
17
- document_anchors.
18
- map { |link| extract_href_from_link(link) }.
19
- reject(&:blank?)
17
+ document_anchors
18
+ .map { |link| extract_href_from_link(link) }
19
+ .reject(&:blank?)
20
20
  end
21
21
 
22
22
  def extract_href_from_link(link)
@@ -92,11 +92,13 @@ module Govspeak
92
92
  end
93
93
 
94
94
  document.css(":not(thead) tr td:first-child").map do |el|
95
- if el.content.match?(/^#($|\s.*$)/)
96
- el.content = el.content.gsub(/^#($|\s)/, "") # Replace '# ' and '#', but not '#Word'.
97
- el.name = "th" if el.content.present? # This also prevents a `th` with nothing inside it; a `td` is preferable.
98
- el[:scope] = "row" if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
99
- end
95
+ next unless el.content.match?(/^#($|\s.*$)/)
96
+
97
+ # Replace '# ' and '#', but not '#Word'.
98
+ # This runs on the first child of the element to preserve any links
99
+ el.children.first.content = el.children.first.content.gsub(/^#($|\s)/, "")
100
+ el.name = "th" if el.content.present? # This also prevents a `th` with nothing inside it; a `td` is preferable.
101
+ el[:scope] = "row" if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
100
102
  end
101
103
  end
102
104
 
@@ -118,6 +120,17 @@ module Govspeak
118
120
  end
119
121
  end
120
122
 
123
+ extension("use custom footnotes") do |document|
124
+ document.css("a.footnote").map do |el|
125
+ footnote_number = el[:href].gsub(/\D/, "")
126
+ el.content = "[footnote #{footnote_number}]"
127
+ end
128
+ document.css("[role='doc-backlink']").map do |el|
129
+ backlink_number = " " + el.css("sup")[0].content if el.css("sup")[0].present?
130
+ el["aria-label"] = "go to where this is referenced#{backlink_number}"
131
+ end
132
+ end
133
+
121
134
  attr_reader :input, :govspeak_document
122
135
 
123
136
  def initialize(html, govspeak_document)
@@ -55,46 +55,46 @@ module Govspeak
55
55
 
56
56
  def humanized_content_type(file_extension)
57
57
  file_extension_vs_humanized_content_type = {
58
- "chm" => file_abbr_tag("CHM", "Microsoft Compiled HTML Help"),
59
- "csv" => file_abbr_tag("CSV", "Comma-separated Values"),
58
+ "chm" => file_abbr_tag("CHM", "Microsoft Compiled HTML Help"),
59
+ "csv" => file_abbr_tag("CSV", "Comma-separated Values"),
60
60
  "diff" => file_abbr_tag("DIFF", "Plain text differences"),
61
- "doc" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
61
+ "doc" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
62
62
  "docx" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
63
- "dot" => file_abbr_tag("DOT", "MS Word Document Template"),
64
- "dxf" => file_abbr_tag("DXF", "AutoCAD Drawing Exchange Format"),
65
- "eps" => file_abbr_tag("EPS", "Encapsulated PostScript"),
66
- "gif" => file_abbr_tag("GIF", "Graphics Interchange Format"),
67
- "gml" => file_abbr_tag("GML", "Geography Markup Language"),
63
+ "dot" => file_abbr_tag("DOT", "MS Word Document Template"),
64
+ "dxf" => file_abbr_tag("DXF", "AutoCAD Drawing Exchange Format"),
65
+ "eps" => file_abbr_tag("EPS", "Encapsulated PostScript"),
66
+ "gif" => file_abbr_tag("GIF", "Graphics Interchange Format"),
67
+ "gml" => file_abbr_tag("GML", "Geography Markup Language"),
68
68
  "html" => file_abbr_tag("HTML", "Hypertext Markup Language"),
69
69
  "ics" => file_abbr_tag("ICS", "iCalendar file"),
70
- "jpg" => "JPEG",
71
- "odp" => file_abbr_tag("ODP", "OpenDocument Presentation"),
72
- "ods" => file_abbr_tag("ODS", "OpenDocument Spreadsheet"),
73
- "odt" => file_abbr_tag("ODT", "OpenDocument Text document"),
74
- "pdf" => file_abbr_tag("PDF", "Portable Document Format"),
75
- "png" => file_abbr_tag("PNG", "Portable Network Graphic"),
76
- "ppt" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
70
+ "jpg" => "JPEG",
71
+ "odp" => file_abbr_tag("ODP", "OpenDocument Presentation"),
72
+ "ods" => file_abbr_tag("ODS", "OpenDocument Spreadsheet"),
73
+ "odt" => file_abbr_tag("ODT", "OpenDocument Text document"),
74
+ "pdf" => file_abbr_tag("PDF", "Portable Document Format"),
75
+ "png" => file_abbr_tag("PNG", "Portable Network Graphic"),
76
+ "ppt" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
77
77
  "pptx" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
78
- "ps" => file_abbr_tag("PS", "PostScript"),
79
- "rdf" => file_abbr_tag("RDF", "Resource Description Framework"),
80
- "rtf" => file_abbr_tag("RTF", "Rich Text Format"),
81
- "sch" => file_abbr_tag("SCH", "XML based Schematic"),
82
- "txt" => "Plain text",
78
+ "ps" => file_abbr_tag("PS", "PostScript"),
79
+ "rdf" => file_abbr_tag("RDF", "Resource Description Framework"),
80
+ "rtf" => file_abbr_tag("RTF", "Rich Text Format"),
81
+ "sch" => file_abbr_tag("SCH", "XML based Schematic"),
82
+ "txt" => "Plain text",
83
83
  "wsdl" => file_abbr_tag("WSDL", "Web Services Description Language"),
84
- "xls" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
84
+ "xls" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
85
85
  "xlsm" => file_abbr_tag("XLSM", "MS Excel Macro-Enabled Workbook"),
86
86
  "xlsx" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
87
- "xlt" => file_abbr_tag("XLT", "MS Excel Spreadsheet Template"),
88
- "xsd" => file_abbr_tag("XSD", "XML Schema"),
87
+ "xlt" => file_abbr_tag("XLT", "MS Excel Spreadsheet Template"),
88
+ "xsd" => file_abbr_tag("XSD", "XML Schema"),
89
89
  "xslt" => file_abbr_tag("XSLT", "Extensible Stylesheet Language Transformation"),
90
- "zip" => file_abbr_tag("ZIP", "Zip archive"),
90
+ "zip" => file_abbr_tag("ZIP", "Zip archive"),
91
91
  }
92
92
  file_extension_vs_humanized_content_type.fetch(file_extension.to_s.downcase, "")
93
93
  end
94
94
 
95
95
  def link(body, url, options = {})
96
- options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
97
- %{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
96
+ options_str = options.map { |k, v| %(#{encode(k)}="#{encode(v)}") }.join(" ")
97
+ %(<a href="#{encode(url)}" #{options_str}>#{body}</a>)
98
98
  end
99
99
 
100
100
  private
@@ -33,8 +33,8 @@ module Govspeak
33
33
  def figcaption_html
34
34
  lines = []
35
35
  lines << "<figcaption>"
36
- lines << %{<p>#{caption}</p>} if caption.present?
37
- lines << %{<p>#{I18n.t('govspeak.image.figure.credit', credit: credit)}</p>} if credit.present?
36
+ lines << %(<p>#{caption}</p>) if caption.present?
37
+ lines << %(<p>#{I18n.t('govspeak.image.figure.credit', credit: credit)}</p>) if credit.present?
38
38
  lines << "</figcaption>"
39
39
  lines.join
40
40
  end
@@ -48,9 +48,9 @@ module Govspeak
48
48
  private :doc, :stack, :structured_headers
49
49
 
50
50
  def headers_list
51
- @headers_list ||= doc.headers.map { |h|
51
+ @headers_list ||= doc.headers.map do |h|
52
52
  StructuredHeader.new(h.text, h.level, h.id, [])
53
- }
53
+ end
54
54
  end
55
55
 
56
56
  def add_top_level(header)
@@ -1,3 +1,3 @@
1
1
  module Govspeak
2
- VERSION = "6.5.4".freeze
2
+ VERSION = "6.5.9".freeze
3
3
  end