govspeak 6.7.1 → 6.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b07175e22a88ddf687631c2a157d00f9649efc118ab3e535d95cbda00918d43
4
- data.tar.gz: 430f7d18852c8fdd549812c0260b118108292f34f2767902217c9d57a80d1f8b
3
+ metadata.gz: 3edb8b047b41d9c15581ec77b6b4ba829dae69f64729265deaf5cad25b91744a
4
+ data.tar.gz: 2e899be9ea70576afb234804213e8697278483a77118dc5f03857bdf7ca0e49d
5
5
  SHA512:
6
- metadata.gz: 0fd6c1d0b6e8a416fdeb6d7aba99868dfb8e9ccf80191666dc771dcdf56a9bf396297569759c172608c31daf7bf75a891914e98713fc0e99b8458220b3dd7934
7
- data.tar.gz: 8a04ab8364ea6ac989b4a1549ce8c4f152ad57988144183f7db00b5b256fce4b5823d79ac611a4078f75ccee5bd1d42f5a81344140979d2066916c2693a35dc4
6
+ metadata.gz: 8779eb8e734e660d3ce9b7e020f18c14792ba1488fb92f59d23455e0cf5474f2ded6d376bd3c25e0b09c7e27362a5e56a271bf1f3084ce60a8cc355d07a97b34
7
+ data.tar.gz: 569414d843883df41a9bd9abbc286b94667e50b0156321468d01008980fd28863ef65e127a422a7e55c4793b649901000a6a474e0450903a801287880fa75af6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## Unreleased
2
2
 
3
+ * Minimum Ruby version specified at 2.6 [215](https://github.com/alphagov/govspeak/pull/215)
4
+
5
+ ## 6.7.2
6
+
7
+ * Fix footnotes in legislative lists [216](https://github.com/alphagov/govspeak/pull/216)
8
+
3
9
  ## 6.7.1
4
10
 
5
11
  * Update failing test [212](https://github.com/alphagov/govspeak/pull/212)
@@ -30,9 +30,10 @@ module Govspeak
30
30
  def find_headers(parent)
31
31
  headers = []
32
32
 
33
- if parent.type == :header
33
+ case parent.type
34
+ when :header
34
35
  headers << build_header(parent)
35
- elsif parent.type == :html_element
36
+ when :html_element
36
37
  parent.children.each do |child|
37
38
  if child.type == :header
38
39
  headers << build_header(child)
@@ -126,7 +126,7 @@ module Govspeak
126
126
  el.content = "[footnote #{footnote_number}]"
127
127
  end
128
128
  document.css("[role='doc-backlink']").map do |el|
129
- backlink_number = " " + el.css("sup")[0].content if el.css("sup")[0].present?
129
+ backlink_number = " #{el.css('sup')[0].content}" if el.css("sup")[0].present?
130
130
  el["aria-label"] = "go to where this is referenced#{backlink_number}"
131
131
  end
132
132
  end
@@ -4,6 +4,7 @@ require "htmlentities"
4
4
  module Govspeak
5
5
  class AttachmentPresenter
6
6
  attr_reader :attachment
7
+
7
8
  include ActionView::Helpers::TagHelper
8
9
  include ActionView::Helpers::NumberHelper
9
10
  include ActionView::Helpers::TextHelper
@@ -25,7 +26,7 @@ module Govspeak
25
26
  end
26
27
 
27
28
  def file_extension
28
- # Note: this is a separate parameter rather than being calculated from the
29
+ # NOTE: this is a separate parameter rather than being calculated from the
29
30
  # filename because at the time of writing not all apps were using the effects
30
31
  # of this field.
31
32
  attachment[:file_extension]
@@ -23,30 +23,30 @@ module Govspeak
23
23
 
24
24
  def post_addresses
25
25
  @post_addresses ||= begin
26
- addresses = contact.dig(:details, :post_addresses) || []
27
- filter_post_addresses(addresses)
28
- end
26
+ addresses = contact.dig(:details, :post_addresses) || []
27
+ filter_post_addresses(addresses)
28
+ end
29
29
  end
30
30
 
31
31
  def email_addresses
32
32
  @email_addresses ||= begin
33
- emails = contact.dig(:details, :email_addresses) || []
34
- emails.select { |e| e[:email].present? }
35
- end
33
+ emails = contact.dig(:details, :email_addresses) || []
34
+ emails.select { |e| e[:email].present? }
35
+ end
36
36
  end
37
37
 
38
38
  def phone_numbers
39
39
  @phone_numbers ||= begin
40
- phone_numbers = contact.dig(:details, :phone_numbers) || []
41
- phone_numbers.select { |p| p[:number].present? }
42
- end
40
+ phone_numbers = contact.dig(:details, :phone_numbers) || []
41
+ phone_numbers.select { |p| p[:number].present? }
42
+ end
43
43
  end
44
44
 
45
45
  def contact_form_links
46
46
  @contact_form_links ||= begin
47
- contact_form_links = contact.dig(:details, :contact_form_links) || []
48
- contact_form_links.select { |c| c[:link].present? }
49
- end
47
+ contact_form_links = contact.dig(:details, :contact_form_links) || []
48
+ contact_form_links.select { |c| c[:link].present? }
49
+ end
50
50
  end
51
51
 
52
52
  private
@@ -1,3 +1,3 @@
1
1
  module Govspeak
2
- VERSION = "6.7.1".freeze
2
+ VERSION = "6.7.2".freeze
3
3
  end
data/lib/govspeak.rb CHANGED
@@ -62,18 +62,30 @@ module Govspeak
62
62
  sanitize: true,
63
63
  syntax_highlighter: nil }.merge(options)
64
64
  @options[:entity_output] = :symbolic
65
+ @footnote_definition_html = nil
66
+ @acronyms = []
65
67
  end
66
68
 
67
69
  def to_html
68
70
  @to_html ||= begin
69
- html = if @options[:sanitize]
70
- HtmlSanitizer.new(kramdown_doc.to_html).sanitize(allowed_elements: @allowed_elements)
71
- else
72
- kramdown_doc.to_html
73
- end
71
+ html = if @options[:sanitize]
72
+ HtmlSanitizer.new(kramdown_doc.to_html).sanitize(allowed_elements: @allowed_elements)
73
+ else
74
+ kramdown_doc.to_html
75
+ end
76
+
77
+ unless @footnote_definition_html.nil?
78
+ regex = /<div class="footnotes".*[<\/div>]/m
79
+
80
+ if html.scan(regex).empty?
81
+ html << @footnote_definition_html
82
+ else
83
+ html.gsub!(regex, @footnote_definition_html)
84
+ end
85
+ end
74
86
 
75
- Govspeak::PostProcessor.process(html, self)
76
- end
87
+ Govspeak::PostProcessor.process(html, self)
88
+ end
77
89
  end
78
90
 
79
91
  def to_liquid
@@ -110,6 +122,9 @@ module Govspeak
110
122
  def preprocess(source)
111
123
  source = Govspeak::BlockquoteExtraQuoteRemover.remove(source)
112
124
  source = remove_forbidden_characters(source)
125
+
126
+ legislative_list_footnote_definitions(source)
127
+
113
128
  self.class.extensions.each do |_, regexp, block|
114
129
  source.gsub!(regexp) do
115
130
  instance_exec(*Regexp.last_match.captures, &block)
@@ -118,6 +133,40 @@ module Govspeak
118
133
  source
119
134
  end
120
135
 
136
+ def legislative_list_footnote_definitions(source)
137
+ is_legislative_list = source.scan(/\$LegislativeList.*?\[\^\d\]*.*?\$EndLegislativeList/m).size.positive?
138
+ footnotes = source.scan(/\[\^(\d)\]:(.*)/)
139
+ @acronyms = source.scan(/(?<=\*)\[(.*)\]:(.*)/)
140
+
141
+ if is_legislative_list && footnotes.size.positive?
142
+ list_items = footnotes.map do |footnote|
143
+ number = footnote[0]
144
+ text = footnote[1].strip
145
+ footnote_definition = Govspeak::Document.new(text).to_html[/(?<=<p>).*(?=<\/p>)/]
146
+
147
+ <<~HTML_SNIPPET
148
+ <li id="fn:#{number}" role="doc-endnote">
149
+ <p>
150
+ #{footnote_definition}<a href="#fnref:#{number}" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
151
+ </p>
152
+ </li>
153
+ HTML_SNIPPET
154
+ end
155
+
156
+ @footnote_definition_html = <<~HTML_CONTAINER
157
+ <div class="footnotes" role="doc-endnotes">
158
+ <ol>
159
+ #{list_items.join.strip}
160
+ </ol>
161
+ </div>
162
+ HTML_CONTAINER
163
+ end
164
+
165
+ unless @footnote_definition_html.nil? && @acronyms.size.positive?
166
+ add_acronym_alt_text(@footnote_definition_html)
167
+ end
168
+ end
169
+
121
170
  def remove_forbidden_characters(source)
122
171
  # These are characters that are not deemed not suitable for
123
172
  # markup: https://www.w3.org/TR/unicode-xml/#Charlist
@@ -161,7 +210,7 @@ module Govspeak
161
210
  ([^)]+) # capture inside of link text markdown
162
211
  \) # match end of link text markdown
163
212
  \s* # any whitespace between opening bracket and link
164
- {\/button} # match ending bracket
213
+ {/button} # match ending bracket
165
214
  (?:\r|\n|$) # non-capturing match to make sure end of line and linebreak
166
215
  }x) do |attributes, text, href|
167
216
  button_classes = "govuk-button"
@@ -295,6 +344,18 @@ module Govspeak
295
344
  doc.gsub!("<ul>", "<ol>")
296
345
  doc.gsub!("</ul>", "</ol>")
297
346
  doc.sub!("<ol>", '<ol class="legislative-list">')
347
+
348
+ footnotes = body.scan(/\[\^(\d+)\]/).flatten
349
+
350
+ footnotes.each do |footnote|
351
+ html = "<sup id=\"fnref:#{footnote}\" role=\"doc-noteref\">" \
352
+ "<a href=\"#fn:#{footnote}\" class=\"footnote\" rel=\"footnote\">" \
353
+ "[footnote #{footnote}]</a></sup>"
354
+
355
+ doc.sub!(/(\[\^#{footnote}\])/, html)
356
+ end
357
+
358
+ add_acronym_alt_text(doc) if @acronyms.size.positive?
298
359
  end
299
360
  end
300
361
  end
@@ -386,6 +447,12 @@ module Govspeak
386
447
  def encode(text)
387
448
  HTMLEntities.new.encode(text)
388
449
  end
450
+
451
+ def add_acronym_alt_text(html)
452
+ @acronyms.each do |acronym|
453
+ html.gsub!(acronym[0], "<abbr title=\"#{acronym[1].strip}\">#{acronym[0]}</abbr>")
454
+ end
455
+ end
389
456
  end
390
457
  end
391
458
 
@@ -17,7 +17,7 @@ class GovspeakAttachmentTest < Minitest::Test
17
17
  }
18
18
 
19
19
  rendered = render_govspeak("[Attachment:attachment.pdf]", [attachment])
20
- assert_match(/<section class="gem-c-attachment">/, rendered)
20
+ assert_match(/<section class="gem-c-attachment/, rendered)
21
21
  assert_match(/Attachment Title/, rendered)
22
22
  end
23
23
 
@@ -32,7 +32,7 @@ class GovspeakAttachmentTest < Minitest::Test
32
32
  assert_equal("<p>some text [Attachment:attachment.pdf]</p>\n", rendered)
33
33
 
34
34
  rendered = render_govspeak("[Attachment:attachment.pdf] some text", [attachment])
35
- assert_match(/<section class="gem-c-attachment">/, rendered)
35
+ assert_match(/<section class="gem-c-attachment/, rendered)
36
36
  assert_match(/<p>some text<\/p>/, rendered)
37
37
  end
38
38
  end
@@ -15,7 +15,7 @@ class GovspeakAttachmentsImageTest < Minitest::Test
15
15
  end
16
16
 
17
17
  def compress_html(html)
18
- html.gsub(/[\n\r]+[\s]*/, "")
18
+ html.gsub(/[\n\r]+\s*/, "")
19
19
  end
20
20
 
21
21
  test "renders an empty string for an image attachment not found" do
@@ -7,34 +7,34 @@ class GovspeakTest < Minitest::Test
7
7
  include GovspeakTestHelper
8
8
 
9
9
  test_given_govspeak "{button start cross-domain-tracking:UA-23066786-5}[Start now](https://www.registertovote.service.gov.uk/register-to-vote/start){/button}" do
10
- assert_html_output '<p><a class="gem-c-button govuk-button govuk-button--start" role="button" data-module="cross-domain-tracking" data-tracking-code="UA-23066786-5" data-tracking-name="govspeakButtonTracker" href="https://www.registertovote.service.gov.uk/register-to-vote/start"> Start now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>'
10
+ assert_html_selector 'a.gem-c-button.govuk-button--start[data-module="cross-domain-tracking"][data-tracking-code="UA-23066786-5"][href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
11
11
  assert_text_output "Start now"
12
12
  end
13
13
 
14
14
  # The same as above but with line breaks
15
15
  test_given_govspeak "{button start cross-domain-tracking:UA-23066786-5}\n\n\n[Start now](https://www.registertovote.service.gov.uk/register-to-vote/start)\n\n\n{/button}" do
16
- assert_html_output '<p><a class="gem-c-button govuk-button govuk-button--start" role="button" data-module="cross-domain-tracking" data-tracking-code="UA-23066786-5" data-tracking-name="govspeakButtonTracker" href="https://www.registertovote.service.gov.uk/register-to-vote/start"> Start now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>'
16
+ assert_html_selector 'a.gem-c-button.govuk-button--start[data-module="cross-domain-tracking"][data-tracking-code="UA-23066786-5"][href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
17
17
  assert_text_output "Start now"
18
18
  end
19
19
 
20
20
  test_given_govspeak "{button cross-domain-tracking:UA-23066786-5}[Start now](https://www.registertovote.service.gov.uk/register-to-vote/start){/button}" do
21
- assert_html_output '<p><a class="gem-c-button govuk-button" role="button" data-module="cross-domain-tracking" data-tracking-code="UA-23066786-5" data-tracking-name="govspeakButtonTracker" href="https://www.registertovote.service.gov.uk/register-to-vote/start">Start now</a></p>'
21
+ assert_html_selector 'a.gem-c-button:not(.govuk-button--start)[data-module="cross-domain-tracking"][data-tracking-code="UA-23066786-5"][href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
22
22
  assert_text_output "Start now"
23
23
  end
24
24
 
25
25
  test_given_govspeak "{button start}[Start now](https://www.registertovote.service.gov.uk/register-to-vote/start){/button}" do
26
- assert_html_output '<p><a class="gem-c-button govuk-button govuk-button--start" role="button" href="https://www.registertovote.service.gov.uk/register-to-vote/start"> Start now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>'
26
+ assert_html_selector 'a.gem-c-button.govuk-button--start[href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
27
27
  assert_text_output "Start now"
28
28
  end
29
29
 
30
30
  test_given_govspeak "{button}[Start now](https://www.registertovote.service.gov.uk/register-to-vote/start){/button}" do
31
- assert_html_output '<p><a class="gem-c-button govuk-button" role="button" href="https://www.registertovote.service.gov.uk/register-to-vote/start">Start now</a></p>'
31
+ assert_html_selector 'a.gem-c-button:not(.govuk-button--start)[href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
32
32
  assert_text_output "Start now"
33
33
  end
34
34
 
35
35
  # Test other text outputs
36
36
  test_given_govspeak "{button}[Something else](https://www.registertovote.service.gov.uk/register-to-vote/start){/button}" do
37
- assert_html_output '<p><a class="gem-c-button govuk-button" role="button" href="https://www.registertovote.service.gov.uk/register-to-vote/start">Something else</a></p>'
37
+ assert_html_selector 'a.gem-c-button[href="https://www.registertovote.service.gov.uk/register-to-vote/start"]'
38
38
  assert_text_output "Something else"
39
39
  end
40
40
 
@@ -54,22 +54,6 @@ class GovspeakTest < Minitest::Test
54
54
  assert_text_output "Text before the button with line breaks Start Now test after the button"
55
55
  end
56
56
 
57
- # Test README examples
58
- test_given_govspeak "{button}[Continue](https://gov.uk/random){/button}" do
59
- assert_html_output '<p><a class="gem-c-button govuk-button" role="button" href="https://gov.uk/random">Continue</a></p>'
60
- assert_text_output "Continue"
61
- end
62
-
63
- test_given_govspeak "{button start}[Start Now](https://gov.uk/random){/button}" do
64
- assert_html_output '<p><a class="gem-c-button govuk-button govuk-button--start" role="button" href="https://gov.uk/random"> Start Now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>'
65
- assert_text_output "Start Now"
66
- end
67
-
68
- test_given_govspeak "{button start cross-domain-tracking:UA-XXXXXX-Y}[Start Now](https://example.com/external-service/start-now){/button}" do
69
- assert_html_output '<p><a class="gem-c-button govuk-button govuk-button--start" role="button" data-module="cross-domain-tracking" data-tracking-code="UA-XXXXXX-Y" data-tracking-name="govspeakButtonTracker" href="https://example.com/external-service/start-now"> Start Now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>'
70
- assert_text_output "Start Now"
71
- end
72
-
73
57
  # Test indenting button govspeak results in no render, useful in guides
74
58
  test_given_govspeak " {button start cross-domain-tracking:UA-XXXXXX-Y}[Example](https://example.com/external-service/start-now){/button}" do
75
59
  assert_html_output %{
@@ -107,7 +91,7 @@ class GovspeakTest < Minitest::Test
107
91
  lorem lorem lorem
108
92
  lorem lorem lorem
109
93
 
110
- {button start}[Start Now](https://gov.uk/random){/button}
94
+ {button}[Random page](https://gov.uk/random){/button}
111
95
 
112
96
  lorem lorem lorem
113
97
  lorem lorem lorem
@@ -120,7 +104,7 @@ class GovspeakTest < Minitest::Test
120
104
  <p>lorem lorem lorem
121
105
  lorem lorem lorem</p>
122
106
 
123
- <p><a class="gem-c-button govuk-button govuk-button--start" role="button" href="https://gov.uk/random"> Start Now <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewbox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg></a></p>
107
+ <p><a class="gem-c-button govuk-button" role="button" href="https://gov.uk/random">Random page</a></p>
124
108
 
125
109
  <p>lorem lorem lorem
126
110
  lorem lorem lorem</p>
@@ -51,7 +51,7 @@ class GovspeakContactsTest < Minitest::Test
51
51
  end
52
52
 
53
53
  def compress_html(html)
54
- html.gsub(/[\n\r]+[\s]*/, "")
54
+ html.gsub(/[\n\r]+\s*/, "")
55
55
  end
56
56
 
57
57
  test "contact is rendered when present in options[:contacts]" do
@@ -18,9 +18,7 @@ class GovspeakImagesBangTest < Minitest::Test
18
18
  test "!!n syntax renders an image in options[:images]" do
19
19
  given_govspeak "!!1", images: [Image.new] do
20
20
  assert_html_output(
21
- %(<figure class="image embedded">) +
22
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
23
- %(</figure>),
21
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
24
22
  )
25
23
  end
26
24
  end
@@ -28,9 +26,7 @@ class GovspeakImagesBangTest < Minitest::Test
28
26
  test "!!n syntax escapes alt text" do
29
27
  given_govspeak "!!1", images: [Image.new(alt_text: %(my alt '&"<>))] do
30
28
  assert_html_output(
31
- %(<figure class="image embedded">) +
32
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt '&amp;&quot;&lt;&gt;"></div>) +
33
- %(</figure>),
29
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt '&amp;&quot;&lt;&gt;\"></div></figure>",
34
30
  )
35
31
  end
36
32
  end
@@ -48,10 +44,7 @@ class GovspeakImagesBangTest < Minitest::Test
48
44
  test "!!n syntax adds image caption if given" do
49
45
  given_govspeak "!!1", images: [Image.new(caption: "My Caption & so on")] do
50
46
  assert_html_output(
51
- %(<figure class="image embedded">) +
52
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
53
- %(<figcaption><p>My Caption &amp; so on</p></figcaption>) +
54
- %(</figure>),
47
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>My Caption &amp; so on</p></figcaption></figure>",
55
48
  )
56
49
  end
57
50
  end
@@ -59,9 +52,7 @@ class GovspeakImagesBangTest < Minitest::Test
59
52
  test "!!n syntax ignores a blank caption" do
60
53
  given_govspeak "!!1", images: [Image.new(caption: " ")] do
61
54
  assert_html_output(
62
- %(<figure class="image embedded">) +
63
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
64
- %(</figure>),
55
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
65
56
  )
66
57
  end
67
58
  end
@@ -69,10 +60,7 @@ class GovspeakImagesBangTest < Minitest::Test
69
60
  test "¡¡n syntax adds image credit if given" do
70
61
  given_govspeak "!!1", images: [Image.new(credit: "My Credit & so on")] do
71
62
  assert_html_output(
72
- %(<figure class="image embedded">) +
73
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
74
- %(<figcaption><p>Image credit: My Credit &amp; so on</p></figcaption>) +
75
- %(</figure>),
63
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>Image credit: My Credit &amp; so on</p></figcaption></figure>",
76
64
  )
77
65
  end
78
66
  end
@@ -80,9 +68,7 @@ class GovspeakImagesBangTest < Minitest::Test
80
68
  test "!!n syntax ignores a blank credit" do
81
69
  given_govspeak "!!1", images: [Image.new(credit: " ")] do
82
70
  assert_html_output(
83
- %(<figure class="image embedded">) +
84
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
85
- %(</figure>),
71
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
86
72
  )
87
73
  end
88
74
  end
@@ -90,13 +76,7 @@ class GovspeakImagesBangTest < Minitest::Test
90
76
  test "!!n syntax adds image caption and credit if given" do
91
77
  given_govspeak "!!1", images: [Image.new(caption: "My Caption & so on", credit: "My Credit & so on")] do
92
78
  assert_html_output(
93
- %(<figure class="image embedded">) +
94
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
95
- %(<figcaption>) +
96
- %(<p>My Caption &amp; so on</p>\n) +
97
- %(<p>Image credit: My Credit &amp; so on</p>) +
98
- %(</figcaption>) +
99
- %(</figure>),
79
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>My Caption &amp; so on</p>\n<p>Image credit: My Credit &amp; so on</p></figcaption></figure>",
100
80
  )
101
81
  end
102
82
  end
@@ -14,9 +14,7 @@ class GovspeakImagesTest < Minitest::Test
14
14
  test "Image:image-id syntax renders an image in options[:images]" do
15
15
  given_govspeak "[Image:image-id]", images: [build_image] do
16
16
  assert_html_output(
17
- %(<figure class="image embedded">) +
18
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
19
- %(</figure>),
17
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
20
18
  )
21
19
  end
22
20
  end
@@ -24,9 +22,7 @@ class GovspeakImagesTest < Minitest::Test
24
22
  test "Image:image-id syntax escapes alt text" do
25
23
  given_govspeak "[Image:image-id]", images: [build_image(alt_text: %(my alt '&"<>))] do
26
24
  assert_html_output(
27
- %(<figure class="image embedded">) +
28
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt '&amp;&quot;&lt;&gt;"></div>) +
29
- %(</figure>),
25
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt '&amp;&quot;&lt;&gt;\"></div></figure>",
30
26
  )
31
27
  end
32
28
  end
@@ -39,10 +35,7 @@ class GovspeakImagesTest < Minitest::Test
39
35
  test "Image:image-id syntax adds image caption if given" do
40
36
  given_govspeak "[Image:image-id]", images: [build_image(caption: "My Caption & so on")] do
41
37
  assert_html_output(
42
- %(<figure class="image embedded">) +
43
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
44
- %(<figcaption><p>My Caption &amp; so on</p></figcaption>) +
45
- %(</figure>),
38
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>My Caption &amp; so on</p></figcaption></figure>",
46
39
  )
47
40
  end
48
41
  end
@@ -50,9 +43,7 @@ class GovspeakImagesTest < Minitest::Test
50
43
  test "Image:image-id syntax ignores a blank caption" do
51
44
  given_govspeak "[Image:image-id]", images: [build_image(caption: " ")] do
52
45
  assert_html_output(
53
- %(<figure class="image embedded">) +
54
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
55
- %(</figure>),
46
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
56
47
  )
57
48
  end
58
49
  end
@@ -60,10 +51,7 @@ class GovspeakImagesTest < Minitest::Test
60
51
  test "Image:image-id syntax adds image credit if given" do
61
52
  given_govspeak "[Image:image-id]", images: [build_image(credit: "My Credit & so on")] do
62
53
  assert_html_output(
63
- %(<figure class="image embedded">) +
64
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
65
- %(<figcaption><p>Image credit: My Credit &amp; so on</p></figcaption>) +
66
- %(</figure>),
54
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>Image credit: My Credit &amp; so on</p></figcaption></figure>",
67
55
  )
68
56
  end
69
57
  end
@@ -71,9 +59,7 @@ class GovspeakImagesTest < Minitest::Test
71
59
  test "Image:image-id syntax ignores a blank credit" do
72
60
  given_govspeak "[Image:image-id]", images: [build_image(credit: " ")] do
73
61
  assert_html_output(
74
- %(<figure class="image embedded">) +
75
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
76
- %(</figure>),
62
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
77
63
  )
78
64
  end
79
65
  end
@@ -81,13 +67,7 @@ class GovspeakImagesTest < Minitest::Test
81
67
  test "Image:image-id syntax adds image caption and credit if given" do
82
68
  given_govspeak "[Image:image-id]", images: [build_image(caption: "My Caption & so on", credit: "My Credit & so on")] do
83
69
  assert_html_output(
84
- %(<figure class="image embedded">) +
85
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>\n) +
86
- %(<figcaption>) +
87
- %(<p>My Caption &amp; so on</p>\n) +
88
- %(<p>Image credit: My Credit &amp; so on</p>) +
89
- %(</figcaption>) +
90
- %(</figure>),
70
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div>\n<figcaption><p>My Caption &amp; so on</p>\n<p>Image credit: My Credit &amp; so on</p></figcaption></figure>",
91
71
  )
92
72
  end
93
73
  end
@@ -99,18 +79,13 @@ class GovspeakImagesTest < Minitest::Test
99
79
 
100
80
  given_govspeak "[Image:image-id]", images: [build_image] do
101
81
  assert_html_output(
102
- %(<figure class="image embedded">) +
103
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
104
- %(</figure>),
82
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>",
105
83
  )
106
84
  end
107
85
 
108
86
  given_govspeak "[Image:image-id] some text", images: [build_image] do
109
87
  assert_html_output(
110
- %(<figure class="image embedded">) +
111
- %(<div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div>) +
112
- %(</figure>\n) +
113
- %(<p>some text</p>),
88
+ "<figure class=\"image embedded\"><div class=\"img\"><img src=\"http://example.com/image.jpg\" alt=\"my alt\"></div></figure>\n<p>some text</p>",
114
89
  )
115
90
  end
116
91
  end
@@ -591,6 +591,213 @@ Teston
591
591
  }
592
592
  end
593
593
 
594
+ test_given_govspeak "
595
+ $LegislativeList
596
+ * 1. Item 1[^1]
597
+ * 2. Item 2[^2]
598
+ * 3. Item 3
599
+ $EndLegislativeList
600
+
601
+ [^1]: Footnote definition one
602
+ [^2]: Footnote definition two
603
+ " do
604
+ assert_html_output %(
605
+ <ol class="legislative-list">
606
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
607
+ </li>
608
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
609
+ </li>
610
+ <li>3. Item 3</li>
611
+ </ol>
612
+
613
+ <div class="footnotes" role="doc-endnotes">
614
+ <ol>
615
+ <li id="fn:1" role="doc-endnote">
616
+ <p>
617
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
618
+ </p>
619
+ </li>
620
+ <li id="fn:2" role="doc-endnote">
621
+ <p>
622
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
623
+ </p>
624
+ </li>
625
+ </ol>
626
+ </div>
627
+ )
628
+ end
629
+
630
+ test_given_govspeak "
631
+ $LegislativeList
632
+ * 1. Item 1[^1]
633
+ * 2. Item 2
634
+ * 3. Item 3
635
+ $EndLegislativeList
636
+
637
+ This is a paragraph with a footnote[^2].
638
+
639
+ $LegislativeList
640
+ * 1. Item 1
641
+ * 2. Item 2[^3]
642
+ * 3. Item 3
643
+ $EndLegislativeList
644
+
645
+ [^1]: Footnote definition one
646
+ [^2]: Footnote definition two
647
+ [^3]: Footnote definition two
648
+ " do
649
+ assert_html_output %(
650
+ <ol class="legislative-list">
651
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
652
+ </li>
653
+ <li>2. Item 2</li>
654
+ <li>3. Item 3</li>
655
+ </ol>
656
+
657
+ <p>This is a paragraph with a footnote<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>.</p>
658
+
659
+ <ol class="legislative-list">
660
+ <li>1. Item 1</li>
661
+ <li>2. Item 2<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>
662
+ </li>
663
+ <li>3. Item 3</li>
664
+ </ol>
665
+
666
+ <div class="footnotes" role="doc-endnotes">
667
+ <ol>
668
+ <li id="fn:1" role="doc-endnote">
669
+ <p>
670
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
671
+ </p>
672
+ </li>
673
+ <li id="fn:2" role="doc-endnote">
674
+ <p>
675
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
676
+ </p>
677
+ </li>
678
+ <li id="fn:3" role="doc-endnote">
679
+ <p>
680
+ Footnote definition two<a href="#fnref:3" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
681
+ </p>
682
+ </li>
683
+ </ol>
684
+ </div>
685
+ )
686
+ end
687
+
688
+ test_given_govspeak "
689
+ $LegislativeList
690
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
691
+ * 2. Item 2
692
+ * 3. Item 3
693
+ $EndLegislativeList
694
+
695
+ This is a paragraph with a footnote[^2]
696
+
697
+ [^1]: Footnote definition one
698
+ [^2]: Footnote definition two
699
+ " do
700
+ assert_html_output %(
701
+ <ol class="legislative-list">
702
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup> with a <a href="http://www.gov.uk">link</a>
703
+ </li>
704
+ <li>2. Item 2</li>
705
+ <li>3. Item 3</li>
706
+ </ol>
707
+
708
+ <p>This is a paragraph with a footnote<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup></p>
709
+
710
+ <div class="footnotes" role="doc-endnotes">
711
+ <ol>
712
+ <li id="fn:1" role="doc-endnote">
713
+ <p>
714
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
715
+ </p>
716
+ </li>
717
+ <li id="fn:2" role="doc-endnote">
718
+ <p>
719
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
720
+ </p>
721
+ </li>
722
+ </ol>
723
+ </div>
724
+ )
725
+ end
726
+
727
+ test_given_govspeak "
728
+ $LegislativeList
729
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
730
+ * 2. Item 2
731
+ * 3. Item 3[^2]
732
+ $EndLegislativeList
733
+
734
+ [^1]: Footnote definition one with a [link](http://www.gov.uk) included
735
+ [^2]: Footnote definition two with an external [link](http://www.google.com)
736
+ " do
737
+ assert_html_output %(
738
+ <ol class="legislative-list">
739
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup> with a <a href="http://www.gov.uk">link</a>
740
+ </li>
741
+ <li>2. Item 2</li>
742
+ <li>3. Item 3<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
743
+ </li>
744
+ </ol>
745
+
746
+ <div class="footnotes" role="doc-endnotes">
747
+ <ol>
748
+ <li id="fn:1" role="doc-endnote">
749
+ <p>
750
+ Footnote definition one with a <a href="http://www.gov.uk">link</a> included<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
751
+ </p>
752
+ </li>
753
+ <li id="fn:2" role="doc-endnote">
754
+ <p>
755
+ Footnote definition two with an external <a rel="external" href="http://www.google.com">link</a><a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
756
+ </p>
757
+ </li>
758
+ </ol>
759
+ </div>
760
+ )
761
+ end
762
+
763
+ test_given_govspeak "
764
+ $LegislativeList
765
+ * 1. Item 1[^1] with an ACRONYM
766
+ * 2. Item 2[^2]
767
+ * 3. Item 3
768
+ $EndLegislativeList
769
+
770
+ [^1]: Footnote definition one
771
+ [^2]: Footnote definition two with an ACRONYM
772
+
773
+ *[ACRONYM]: This is the acronym explanation
774
+ " do
775
+ assert_html_output %(
776
+ <ol class="legislative-list">
777
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup> with an <abbr title="This is the acronym explanation">ACRONYM</abbr>
778
+ </li>
779
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
780
+ </li>
781
+ <li>3. Item 3</li>
782
+ </ol>
783
+
784
+ <div class="footnotes" role="doc-endnotes">
785
+ <ol>
786
+ <li id="fn:1" role="doc-endnote">
787
+ <p>
788
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
789
+ </p>
790
+ </li>
791
+ <li id="fn:2" role="doc-endnote">
792
+ <p>
793
+ Footnote definition two with an <abbr title="This is the acronym explanation">ACRONYM</abbr><a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
794
+ </p>
795
+ </li>
796
+ </ol>
797
+ </div>
798
+ )
799
+ end
800
+
594
801
  test_given_govspeak "
595
802
  The quick brown
596
803
  $LegislativeList
@@ -26,6 +26,12 @@ module GovspeakTestHelper
26
26
  @testcase.assert expected.strip == actual, describe_error(@govspeak, expected.strip, actual)
27
27
  end
28
28
 
29
+ def assert_html_selector(selector)
30
+ html = document.to_html
31
+ fragment = Nokogiri::HTML.fragment(html)
32
+ @testcase.assert fragment.css(selector).any?, "Expected to find #{selector} within #{html}"
33
+ end
34
+
29
35
  def remove_indentation(raw)
30
36
  lines = raw.split("\n")
31
37
  if lines.first.empty?
@@ -33,7 +39,7 @@ module GovspeakTestHelper
33
39
  nonblanks = lines.reject { |l| l.match(/^ *$/) }
34
40
  indentation = nonblanks.map { |line| line.match(/^ */)[0].size }.min
35
41
  unindented = lines.map do |line|
36
- line[indentation..-1]
42
+ line[indentation..]
37
43
  end
38
44
  unindented.join "\n"
39
45
  else
data/test/test_helper.rb CHANGED
@@ -17,10 +17,10 @@ class Minitest::Test
17
17
  clean_name = name.gsub(/\s+/, "_")
18
18
  method = "test_#{clean_name.gsub(/\s+/, '_')}".to_sym
19
19
  already_defined = begin
20
- instance_method(method)
21
- rescue StandardError
22
- false
23
- end
20
+ instance_method(method)
21
+ rescue StandardError
22
+ false
23
+ end
24
24
  raise "#{method} exists" if already_defined
25
25
 
26
26
  define_method(method, &block)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govspeak
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.7.1
4
+ version: 6.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-17 00:00:00.000000000 Z
11
+ date: 2021-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -216,14 +216,14 @@ dependencies:
216
216
  requirements:
217
217
  - - "~>"
218
218
  - !ruby/object:Gem::Version
219
- version: 3.17.1
219
+ version: 4.0.0
220
220
  type: :development
221
221
  prerelease: false
222
222
  version_requirements: !ruby/object:Gem::Requirement
223
223
  requirements:
224
224
  - - "~>"
225
225
  - !ruby/object:Gem::Version
226
- version: 3.17.1
226
+ version: 4.0.0
227
227
  - !ruby/object:Gem::Dependency
228
228
  name: simplecov
229
229
  requirement: !ruby/object:Gem::Requirement
@@ -360,36 +360,36 @@ required_ruby_version: !ruby/object:Gem::Requirement
360
360
  requirements:
361
361
  - - ">="
362
362
  - !ruby/object:Gem::Version
363
- version: '0'
363
+ version: '2.6'
364
364
  required_rubygems_version: !ruby/object:Gem::Requirement
365
365
  requirements:
366
366
  - - ">="
367
367
  - !ruby/object:Gem::Version
368
368
  version: '0'
369
369
  requirements: []
370
- rubygems_version: 3.1.4
370
+ rubygems_version: 3.0.3
371
371
  signing_key:
372
372
  specification_version: 4
373
373
  summary: Markup language for single domain
374
374
  test_files:
375
- - test/govspeak_images_bang_test.rb
376
- - test/govspeak_attachment_test.rb
377
- - test/govspeak_link_extractor_test.rb
378
- - test/govspeak_attachments_inline_test.rb
379
- - test/govspeak_button_test.rb
380
- - test/govspeak_structured_headers_test.rb
381
375
  - test/govspeak_attachments_image_test.rb
382
- - test/govspeak_attachment_link_test.rb
376
+ - test/govspeak_structured_headers_test.rb
377
+ - test/govspeak_images_bang_test.rb
378
+ - test/govspeak_link_test.rb
383
379
  - test/govspeak_extract_contact_content_ids_test.rb
384
- - test/presenters/h_card_presenter_test.rb
385
- - test/govspeak_test.rb
386
- - test/html_sanitizer_test.rb
387
- - test/govspeak_footnote_test.rb
380
+ - test/govspeak_test_helper.rb
388
381
  - test/blockquote_extra_quote_remover_test.rb
382
+ - test/govspeak_attachments_inline_test.rb
383
+ - test/govspeak_attachment_test.rb
389
384
  - test/test_helper.rb
390
- - test/govspeak_table_with_headers_test.rb
385
+ - test/govspeak_test.rb
386
+ - test/presenters/h_card_presenter_test.rb
387
+ - test/govspeak_footnote_test.rb
388
+ - test/govspeak_attachment_link_test.rb
389
+ - test/govspeak_link_extractor_test.rb
390
+ - test/govspeak_button_test.rb
391
391
  - test/govspeak_images_test.rb
392
- - test/govspeak_link_test.rb
393
392
  - test/html_validator_test.rb
393
+ - test/html_sanitizer_test.rb
394
+ - test/govspeak_table_with_headers_test.rb
394
395
  - test/govspeak_contacts_test.rb
395
- - test/govspeak_test_helper.rb