govspeak 6.7.1 → 6.7.5

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: fb4fa452bfd1c6f1cdff6b638f91dfbc9961ea2bd7568f4feadd12fe73772532
4
+ data.tar.gz: 925ff3efcbb3b3a9a1aa6e0319e9f5a3ec1540febd0168b8517c5aa884e6e69c
5
5
  SHA512:
6
- metadata.gz: 0fd6c1d0b6e8a416fdeb6d7aba99868dfb8e9ccf80191666dc771dcdf56a9bf396297569759c172608c31daf7bf75a891914e98713fc0e99b8458220b3dd7934
7
- data.tar.gz: 8a04ab8364ea6ac989b4a1549ce8c4f152ad57988144183f7db00b5b256fce4b5823d79ac611a4078f75ccee5bd1d42f5a81344140979d2066916c2693a35dc4
6
+ metadata.gz: 574ea02a4f90e336a7c2a3b6642a7c1fe91924e8d71f4c55eb71053875c607c19de73aefbb34218d0cbe563c8e95982baf18ce42860a1002e58008efab20a93e
7
+ data.tar.gz: db21f5a85823c27024ff78970ec8d8dab64584910f90fdbed5649516abfbf5110fca8c52c99b978c54db3e060e1c654ac46e0995b87f5b8ab400c9dfa971b756
data/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
- ## Unreleased
1
+ ## 6.7.5
2
+
3
+ * Fix footnotes in call-to-action boxes [222](https://github.com/alphagov/govspeak/pull/222)
4
+
5
+ ## 6.7.4
6
+
7
+ * Remove Nokogumbo dependency to [resolve warning](https://github.com/sparklemotion/nokogiri/issues/2205) [220](https://github.com/alphagov/govspeak/pull/220)
8
+
9
+ ## 6.7.3
10
+
11
+ * Fix regex for footnotes in legislative lists [218](https://github.com/alphagov/govspeak/pull/218)
12
+
13
+ ## 6.7.2
14
+
15
+ * Minimum Ruby version specified at 2.6 [215](https://github.com/alphagov/govspeak/pull/215)
16
+ * Fix footnotes in legislative lists [216](https://github.com/alphagov/govspeak/pull/216)
2
17
 
3
18
  ## 6.7.1
4
19
 
@@ -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.5".freeze
3
3
  end
data/lib/govspeak.rb CHANGED
@@ -6,7 +6,6 @@ require "htmlentities"
6
6
  require "kramdown"
7
7
  require "kramdown/parser/govuk"
8
8
  require "nokogiri"
9
- require "nokogumbo"
10
9
  require "rinku"
11
10
  require "sanitize"
12
11
  require "govspeak/header_extractor"
@@ -62,18 +61,30 @@ module Govspeak
62
61
  sanitize: true,
63
62
  syntax_highlighter: nil }.merge(options)
64
63
  @options[:entity_output] = :symbolic
64
+ @footnote_definition_html = nil
65
+ @acronyms = []
65
66
  end
66
67
 
67
68
  def to_html
68
69
  @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
70
+ html = if @options[:sanitize]
71
+ HtmlSanitizer.new(kramdown_doc.to_html).sanitize(allowed_elements: @allowed_elements)
72
+ else
73
+ kramdown_doc.to_html
74
+ end
75
+
76
+ unless @footnote_definition_html.nil?
77
+ regex = /<div class="footnotes".*[<\/div>]/m
78
+
79
+ if html.scan(regex).empty?
80
+ html << @footnote_definition_html
81
+ else
82
+ html.gsub!(regex, @footnote_definition_html)
83
+ end
84
+ end
74
85
 
75
- Govspeak::PostProcessor.process(html, self)
76
- end
86
+ Govspeak::PostProcessor.process(html, self)
87
+ end
77
88
  end
78
89
 
79
90
  def to_liquid
@@ -110,6 +121,9 @@ module Govspeak
110
121
  def preprocess(source)
111
122
  source = Govspeak::BlockquoteExtraQuoteRemover.remove(source)
112
123
  source = remove_forbidden_characters(source)
124
+
125
+ footnote_definitions(source)
126
+
113
127
  self.class.extensions.each do |_, regexp, block|
114
128
  source.gsub!(regexp) do
115
129
  instance_exec(*Regexp.last_match.captures, &block)
@@ -118,6 +132,40 @@ module Govspeak
118
132
  source
119
133
  end
120
134
 
135
+ def footnote_definitions(source)
136
+ is_legislative_list = source.scan(/\$LegislativeList.*?\[\^\d\]*.*?\$EndLegislativeList/m).size.positive?
137
+ is_cta = source.scan(/\$CTA.*?\[\^\d\]*.*?\$CTA/m).size.positive?
138
+ footnotes = source.scan(/\[\^(\d+)\]:(.*)/)
139
+ @acronyms = source.scan(/(?<=\*)\[(.*)\]:(.*)/)
140
+ if (is_legislative_list || is_cta) && footnotes.size.positive?
141
+ list_items = footnotes.map do |footnote|
142
+ number = footnote[0]
143
+ text = footnote[1].strip
144
+ footnote_definition = Govspeak::Document.new(text).to_html[/(?<=<p>).*(?=<\/p>)/]
145
+
146
+ <<~HTML_SNIPPET
147
+ <li id="fn:#{number}" role="doc-endnote">
148
+ <p>
149
+ #{footnote_definition}<a href="#fnref:#{number}" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
150
+ </p>
151
+ </li>
152
+ HTML_SNIPPET
153
+ end
154
+
155
+ @footnote_definition_html = <<~HTML_CONTAINER
156
+ <div class="footnotes" role="doc-endnotes">
157
+ <ol>
158
+ #{list_items.join.strip}
159
+ </ol>
160
+ </div>
161
+ HTML_CONTAINER
162
+ end
163
+
164
+ unless @footnote_definition_html.nil? && @acronyms.size.positive?
165
+ add_acronym_alt_text(@footnote_definition_html)
166
+ end
167
+ end
168
+
121
169
  def remove_forbidden_characters(source)
122
170
  # These are characters that are not deemed not suitable for
123
171
  # markup: https://www.w3.org/TR/unicode-xml/#Charlist
@@ -161,7 +209,7 @@ module Govspeak
161
209
  ([^)]+) # capture inside of link text markdown
162
210
  \) # match end of link text markdown
163
211
  \s* # any whitespace between opening bracket and link
164
- {\/button} # match ending bracket
212
+ {/button} # match ending bracket
165
213
  (?:\r|\n|$) # non-capturing match to make sure end of line and linebreak
166
214
  }x) do |attributes, text, href|
167
215
  button_classes = "govuk-button"
@@ -273,10 +321,26 @@ module Govspeak
273
321
  lines.join
274
322
  end
275
323
 
324
+ extension("call-to-action", surrounded_by("$CTA")) do |body|
325
+ doc = Kramdown::Document.new(body.strip).to_html
326
+ doc = %(\n<div class="call-to-action">\n#{doc}</div>\n)
327
+ footnotes = body.scan(/\[\^(\d+)\]/).flatten
328
+
329
+ footnotes.each do |footnote|
330
+ html = "<sup id=\"fnref:#{footnote}\" role=\"doc-noteref\">" \
331
+ "<a href=\"#fn:#{footnote}\" class=\"footnote\" rel=\"footnote\">" \
332
+ "[footnote #{footnote}]</a></sup>"
333
+
334
+ doc.sub!(/(\[\^#{footnote}\])/, html)
335
+ end
336
+
337
+ add_acronym_alt_text(doc) if @acronyms.size.positive?
338
+ doc
339
+ end
340
+
276
341
  # More specific tags must be defined first. Those defined earlier have a
277
342
  # higher precedence for being matched. For example $CTA must be defined
278
343
  # before $C otherwise the first ($C)TA fill be matched to a contact tag.
279
- wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
280
344
  wrap_with_div("summary", "$!")
281
345
  wrap_with_div("form-download", "$D")
282
346
  wrap_with_div("contact", "$C")
@@ -295,6 +359,18 @@ module Govspeak
295
359
  doc.gsub!("<ul>", "<ol>")
296
360
  doc.gsub!("</ul>", "</ol>")
297
361
  doc.sub!("<ol>", '<ol class="legislative-list">')
362
+
363
+ footnotes = body.scan(/\[\^(\d+)\]/).flatten
364
+
365
+ footnotes.each do |footnote|
366
+ html = "<sup id=\"fnref:#{footnote}\" role=\"doc-noteref\">" \
367
+ "<a href=\"#fn:#{footnote}\" class=\"footnote\" rel=\"footnote\">" \
368
+ "[footnote #{footnote}]</a></sup>"
369
+
370
+ doc.sub!(/(\[\^#{footnote}\])/, html)
371
+ end
372
+
373
+ add_acronym_alt_text(doc) if @acronyms.size.positive?
298
374
  end
299
375
  end
300
376
  end
@@ -386,6 +462,12 @@ module Govspeak
386
462
  def encode(text)
387
463
  HTMLEntities.new.encode(text)
388
464
  end
465
+
466
+ def add_acronym_alt_text(html)
467
+ @acronyms.each do |acronym|
468
+ html.gsub!(acronym[0], "<abbr title=\"#{acronym[1].strip}\">#{acronym[0]}</abbr>")
469
+ end
470
+ end
389
471
  end
390
472
  end
391
473
 
@@ -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
@@ -473,6 +473,101 @@ Teston
473
473
  </div>)
474
474
  end
475
475
 
476
+ test_given_govspeak "
477
+ $CTA
478
+ Click here to start the tool[^1]
479
+ $CTA
480
+ [^1]: Footnote definition one
481
+ " do
482
+ assert_html_output %(
483
+ <div class="call-to-action">
484
+ <p>Click here to start the tool<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup></p>
485
+ </div>
486
+ <div class="footnotes" role="doc-endnotes">
487
+ <ol>
488
+ <li id="fn:1" role="doc-endnote">
489
+ <p>
490
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
491
+ </p>
492
+ </li>
493
+ </ol>
494
+ </div>
495
+ )
496
+ end
497
+
498
+ test_given_govspeak "
499
+ $CTA
500
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
501
+ Fusce felis ante[^1], lobortis non quam sit amet, tempus interdum justo.
502
+ $CTA
503
+ $CTA
504
+ Pellentesque quam enim, egestas sit amet congue sit amet[^2], ultrices vitae arcu.
505
+ Fringilla, metus dui scelerisque est.
506
+ $CTA
507
+ [^1]: Footnote definition one
508
+ [^2]: Footnote definition two
509
+ " do
510
+ assert_html_output %(
511
+ <div class="call-to-action">
512
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
513
+ Fusce felis ante<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>, lobortis non quam sit amet, tempus interdum justo.</p>
514
+ </div>
515
+
516
+ <div class="call-to-action">
517
+ <p>Pellentesque quam enim, egestas sit amet congue sit amet<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>, ultrices vitae arcu.
518
+ Fringilla, metus dui scelerisque est.</p>
519
+ </div>
520
+ <div class="footnotes" role="doc-endnotes">
521
+ <ol>
522
+ <li id="fn:1" role="doc-endnote">
523
+ <p>
524
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
525
+ </p>
526
+ </li>
527
+ <li id="fn:2" role="doc-endnote">
528
+ <p>
529
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
530
+ </p>
531
+ </li>
532
+ </ol>
533
+ </div>
534
+ )
535
+ end
536
+
537
+ test_given_govspeak "
538
+ $CTA
539
+ Click here to start the tool[^1]
540
+ $CTA
541
+
542
+ Lorem ipsum dolor sit amet[^2]
543
+
544
+ [^1]: Footnote definition 1
545
+ [^2]: Footnote definition 2
546
+ " do
547
+ assert_html_output %(
548
+ <div class="call-to-action">
549
+ <p>Click here to start the tool<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup></p>
550
+ </div>
551
+
552
+ <p>Lorem ipsum dolor sit amet<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup></p>
553
+
554
+ <div class="footnotes" role="doc-endnotes">
555
+ <ol>
556
+ <li id="fn:1" role="doc-endnote">
557
+ <p>
558
+ Footnote definition 1<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
559
+ </p>
560
+ </li>
561
+ <li id="fn:2" role="doc-endnote">
562
+ <p>
563
+ Footnote definition 2<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
564
+ </p>
565
+ </li>
566
+ </ol>
567
+ </div>
568
+ )
569
+ end
570
+
476
571
  test_given_govspeak "
477
572
  1. rod
478
573
  2. jane
@@ -591,6 +686,352 @@ Teston
591
686
  }
592
687
  end
593
688
 
689
+ test_given_govspeak "
690
+ $LegislativeList
691
+ * 1. Item 1[^1]
692
+ * 2. Item 2[^2]
693
+ * 3. Item 3
694
+ $EndLegislativeList
695
+
696
+ [^1]: Footnote definition one
697
+ [^2]: Footnote definition two
698
+ " do
699
+ assert_html_output %(
700
+ <ol class="legislative-list">
701
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
702
+ </li>
703
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
704
+ </li>
705
+ <li>3. Item 3</li>
706
+ </ol>
707
+
708
+ <div class="footnotes" role="doc-endnotes">
709
+ <ol>
710
+ <li id="fn:1" role="doc-endnote">
711
+ <p>
712
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
713
+ </p>
714
+ </li>
715
+ <li id="fn:2" role="doc-endnote">
716
+ <p>
717
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
718
+ </p>
719
+ </li>
720
+ </ol>
721
+ </div>
722
+ )
723
+ end
724
+
725
+ test_given_govspeak "
726
+ $LegislativeList
727
+ * 1. Item 1[^1]
728
+ * 2. Item 2
729
+ * 3. Item 3
730
+ $EndLegislativeList
731
+
732
+ This is a paragraph with a footnote[^2].
733
+
734
+ $LegislativeList
735
+ * 1. Item 1
736
+ * 2. Item 2[^3]
737
+ * 3. Item 3
738
+ $EndLegislativeList
739
+
740
+ [^1]: Footnote definition one
741
+ [^2]: Footnote definition two
742
+ [^3]: Footnote definition two
743
+ " do
744
+ assert_html_output %(
745
+ <ol class="legislative-list">
746
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
747
+ </li>
748
+ <li>2. Item 2</li>
749
+ <li>3. Item 3</li>
750
+ </ol>
751
+
752
+ <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>
753
+
754
+ <ol class="legislative-list">
755
+ <li>1. Item 1</li>
756
+ <li>2. Item 2<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>
757
+ </li>
758
+ <li>3. Item 3</li>
759
+ </ol>
760
+
761
+ <div class="footnotes" role="doc-endnotes">
762
+ <ol>
763
+ <li id="fn:1" role="doc-endnote">
764
+ <p>
765
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
766
+ </p>
767
+ </li>
768
+ <li id="fn:2" role="doc-endnote">
769
+ <p>
770
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
771
+ </p>
772
+ </li>
773
+ <li id="fn:3" role="doc-endnote">
774
+ <p>
775
+ Footnote definition two<a href="#fnref:3" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
776
+ </p>
777
+ </li>
778
+ </ol>
779
+ </div>
780
+ )
781
+ end
782
+
783
+ test_given_govspeak "
784
+ $LegislativeList
785
+ * 1. Item 1[^1]
786
+ * 2. Item 2[^2]
787
+ * 3. Item 3[^3]
788
+ $EndLegislativeList
789
+
790
+ This is a paragraph with a footnote[^4].
791
+
792
+ $LegislativeList
793
+ * 1. Item 1[^5]
794
+ * 2. Item 2[^6]
795
+ * 3. Item 3[^7]
796
+ $EndLegislativeList
797
+
798
+ This is a paragraph with a footnote[^8].
799
+
800
+ $LegislativeList
801
+ * 1. Item 1[^9]
802
+ * 2. Item 2[^10]
803
+ * 3. Item 3[^11]
804
+ $EndLegislativeList
805
+
806
+ This is a paragraph with a footnote[^12].
807
+
808
+ [^1]: Footnote definition 1
809
+ [^2]: Footnote definition 2
810
+ [^3]: Footnote definition 3
811
+ [^4]: Footnote definition 4
812
+ [^5]: Footnote definition 5
813
+ [^6]: Footnote definition 6
814
+ [^7]: Footnote definition 7
815
+ [^8]: Footnote definition 8
816
+ [^9]: Footnote definition 9
817
+ [^10]: Footnote definition 10
818
+ [^11]: Footnote definition 11
819
+ [^12]: Footnote definition 12
820
+ " do
821
+ assert_html_output %(
822
+ <ol class="legislative-list">
823
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
824
+ </li>
825
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
826
+ </li>
827
+ <li>3. Item 3<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>
828
+ </li>
829
+ </ol>
830
+
831
+ <p>This is a paragraph with a footnote<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">[footnote 4]</a></sup>.</p>
832
+
833
+ <ol class="legislative-list">
834
+ <li>1. Item 1<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">[footnote 5]</a></sup>
835
+ </li>
836
+ <li>2. Item 2<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">[footnote 6]</a></sup>
837
+ </li>
838
+ <li>3. Item 3<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">[footnote 7]</a></sup>
839
+ </li>
840
+ </ol>
841
+
842
+ <p>This is a paragraph with a footnote<sup id="fnref:8" role="doc-noteref"><a href="#fn:8" class="footnote" rel="footnote">[footnote 8]</a></sup>.</p>
843
+
844
+ <ol class="legislative-list">
845
+ <li>1. Item 1<sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">[footnote 9]</a></sup>
846
+ </li>
847
+ <li>2. Item 2<sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">[footnote 10]</a></sup>
848
+ </li>
849
+ <li>3. Item 3<sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">[footnote 11]</a></sup>
850
+ </li>
851
+ </ol>
852
+
853
+ <p>This is a paragraph with a footnote<sup id="fnref:12" role="doc-noteref"><a href="#fn:12" class="footnote" rel="footnote">[footnote 12]</a></sup>.</p>
854
+
855
+ <div class="footnotes" role="doc-endnotes">
856
+ <ol>
857
+ <li id="fn:1" role="doc-endnote">
858
+ <p>
859
+ Footnote definition 1<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
860
+ </p>
861
+ </li>
862
+ <li id="fn:2" role="doc-endnote">
863
+ <p>
864
+ Footnote definition 2<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
865
+ </p>
866
+ </li>
867
+ <li id="fn:3" role="doc-endnote">
868
+ <p>
869
+ Footnote definition 3<a href="#fnref:3" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
870
+ </p>
871
+ </li>
872
+ <li id="fn:4" role="doc-endnote">
873
+ <p>
874
+ Footnote definition 4<a href="#fnref:4" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
875
+ </p>
876
+ </li>
877
+ <li id="fn:5" role="doc-endnote">
878
+ <p>
879
+ Footnote definition 5<a href="#fnref:5" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
880
+ </p>
881
+ </li>
882
+ <li id="fn:6" role="doc-endnote">
883
+ <p>
884
+ Footnote definition 6<a href="#fnref:6" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
885
+ </p>
886
+ </li>
887
+ <li id="fn:7" role="doc-endnote">
888
+ <p>
889
+ Footnote definition 7<a href="#fnref:7" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
890
+ </p>
891
+ </li>
892
+ <li id="fn:8" role="doc-endnote">
893
+ <p>
894
+ Footnote definition 8<a href="#fnref:8" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
895
+ </p>
896
+ </li>
897
+ <li id="fn:9" role="doc-endnote">
898
+ <p>
899
+ Footnote definition 9<a href="#fnref:9" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
900
+ </p>
901
+ </li>
902
+ <li id="fn:10" role="doc-endnote">
903
+ <p>
904
+ Footnote definition 10<a href="#fnref:10" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
905
+ </p>
906
+ </li>
907
+ <li id="fn:11" role="doc-endnote">
908
+ <p>
909
+ Footnote definition 11<a href="#fnref:11" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
910
+ </p>
911
+ </li>
912
+ <li id="fn:12" role="doc-endnote">
913
+ <p>
914
+ Footnote definition 12<a href="#fnref:12" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
915
+ </p>
916
+ </li>
917
+ </ol>
918
+ </div>
919
+ )
920
+ end
921
+
922
+ test_given_govspeak "
923
+ $LegislativeList
924
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
925
+ * 2. Item 2
926
+ * 3. Item 3
927
+ $EndLegislativeList
928
+
929
+ This is a paragraph with a footnote[^2]
930
+
931
+ [^1]: Footnote definition one
932
+ [^2]: Footnote definition two
933
+ " do
934
+ assert_html_output %(
935
+ <ol class="legislative-list">
936
+ <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>
937
+ </li>
938
+ <li>2. Item 2</li>
939
+ <li>3. Item 3</li>
940
+ </ol>
941
+
942
+ <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>
943
+
944
+ <div class="footnotes" role="doc-endnotes">
945
+ <ol>
946
+ <li id="fn:1" role="doc-endnote">
947
+ <p>
948
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
949
+ </p>
950
+ </li>
951
+ <li id="fn:2" role="doc-endnote">
952
+ <p>
953
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
954
+ </p>
955
+ </li>
956
+ </ol>
957
+ </div>
958
+ )
959
+ end
960
+
961
+ test_given_govspeak "
962
+ $LegislativeList
963
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
964
+ * 2. Item 2
965
+ * 3. Item 3[^2]
966
+ $EndLegislativeList
967
+
968
+ [^1]: Footnote definition one with a [link](http://www.gov.uk) included
969
+ [^2]: Footnote definition two with an external [link](http://www.google.com)
970
+ " do
971
+ assert_html_output %(
972
+ <ol class="legislative-list">
973
+ <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>
974
+ </li>
975
+ <li>2. Item 2</li>
976
+ <li>3. Item 3<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
977
+ </li>
978
+ </ol>
979
+
980
+ <div class="footnotes" role="doc-endnotes">
981
+ <ol>
982
+ <li id="fn:1" role="doc-endnote">
983
+ <p>
984
+ 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>
985
+ </p>
986
+ </li>
987
+ <li id="fn:2" role="doc-endnote">
988
+ <p>
989
+ 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>
990
+ </p>
991
+ </li>
992
+ </ol>
993
+ </div>
994
+ )
995
+ end
996
+
997
+ test_given_govspeak "
998
+ $LegislativeList
999
+ * 1. Item 1[^1] with an ACRONYM
1000
+ * 2. Item 2[^2]
1001
+ * 3. Item 3
1002
+ $EndLegislativeList
1003
+
1004
+ [^1]: Footnote definition one
1005
+ [^2]: Footnote definition two with an ACRONYM
1006
+
1007
+ *[ACRONYM]: This is the acronym explanation
1008
+ " do
1009
+ assert_html_output %(
1010
+ <ol class="legislative-list">
1011
+ <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>
1012
+ </li>
1013
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
1014
+ </li>
1015
+ <li>3. Item 3</li>
1016
+ </ol>
1017
+
1018
+ <div class="footnotes" role="doc-endnotes">
1019
+ <ol>
1020
+ <li id="fn:1" role="doc-endnote">
1021
+ <p>
1022
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
1023
+ </p>
1024
+ </li>
1025
+ <li id="fn:2" role="doc-endnote">
1026
+ <p>
1027
+ 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>
1028
+ </p>
1029
+ </li>
1030
+ </ol>
1031
+ </div>
1032
+ )
1033
+ end
1034
+
594
1035
  test_given_govspeak "
595
1036
  The quick brown
596
1037
  $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.5
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-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -112,28 +112,14 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '1.5'
115
+ version: '1.12'
116
116
  type: :runtime
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '1.5'
123
- - !ruby/object:Gem::Dependency
124
- name: nokogumbo
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - "~>"
128
- - !ruby/object:Gem::Version
129
- version: '2'
130
- type: :runtime
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - "~>"
135
- - !ruby/object:Gem::Version
136
- version: '2'
122
+ version: '1.12'
137
123
  - !ruby/object:Gem::Dependency
138
124
  name: rinku
139
125
  requirement: !ruby/object:Gem::Requirement
@@ -152,20 +138,14 @@ dependencies:
152
138
  name: sanitize
153
139
  requirement: !ruby/object:Gem::Requirement
154
140
  requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- version: 5.2.1
158
- - - "<"
141
+ - - "~>"
159
142
  - !ruby/object:Gem::Version
160
143
  version: '6'
161
144
  type: :runtime
162
145
  prerelease: false
163
146
  version_requirements: !ruby/object:Gem::Requirement
164
147
  requirements:
165
- - - ">="
166
- - !ruby/object:Gem::Version
167
- version: 5.2.1
168
- - - "<"
148
+ - - "~>"
169
149
  - !ruby/object:Gem::Version
170
150
  version: '6'
171
151
  - !ruby/object:Gem::Dependency
@@ -216,14 +196,14 @@ dependencies:
216
196
  requirements:
217
197
  - - "~>"
218
198
  - !ruby/object:Gem::Version
219
- version: 3.17.1
199
+ version: 4.1.0
220
200
  type: :development
221
201
  prerelease: false
222
202
  version_requirements: !ruby/object:Gem::Requirement
223
203
  requirements:
224
204
  - - "~>"
225
205
  - !ruby/object:Gem::Version
226
- version: 3.17.1
206
+ version: 4.1.0
227
207
  - !ruby/object:Gem::Dependency
228
208
  name: simplecov
229
209
  requirement: !ruby/object:Gem::Requirement
@@ -360,36 +340,36 @@ required_ruby_version: !ruby/object:Gem::Requirement
360
340
  requirements:
361
341
  - - ">="
362
342
  - !ruby/object:Gem::Version
363
- version: '0'
343
+ version: '2.6'
364
344
  required_rubygems_version: !ruby/object:Gem::Requirement
365
345
  requirements:
366
346
  - - ">="
367
347
  - !ruby/object:Gem::Version
368
348
  version: '0'
369
349
  requirements: []
370
- rubygems_version: 3.1.4
350
+ rubygems_version: 3.0.3
371
351
  signing_key:
372
352
  specification_version: 4
373
353
  summary: Markup language for single domain
374
354
  test_files:
355
+ - test/test_helper.rb
356
+ - test/blockquote_extra_quote_remover_test.rb
375
357
  - test/govspeak_images_bang_test.rb
376
- - test/govspeak_attachment_test.rb
358
+ - test/govspeak_contacts_test.rb
359
+ - test/govspeak_table_with_headers_test.rb
377
360
  - 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
361
  - test/govspeak_attachments_image_test.rb
382
- - test/govspeak_attachment_link_test.rb
362
+ - test/html_validator_test.rb
363
+ - test/govspeak_button_test.rb
383
364
  - 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
365
+ - test/govspeak_test_helper.rb
387
366
  - test/govspeak_footnote_test.rb
388
- - test/blockquote_extra_quote_remover_test.rb
389
- - test/test_helper.rb
390
- - test/govspeak_table_with_headers_test.rb
391
- - test/govspeak_images_test.rb
392
367
  - test/govspeak_link_test.rb
393
- - test/html_validator_test.rb
394
- - test/govspeak_contacts_test.rb
395
- - test/govspeak_test_helper.rb
368
+ - test/govspeak_structured_headers_test.rb
369
+ - test/html_sanitizer_test.rb
370
+ - test/govspeak_images_test.rb
371
+ - test/govspeak_test.rb
372
+ - test/govspeak_attachment_link_test.rb
373
+ - test/govspeak_attachment_test.rb
374
+ - test/presenters/h_card_presenter_test.rb
375
+ - test/govspeak_attachments_inline_test.rb