govspeak 6.6.0 → 6.7.3

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: 6369a640dd1ca0303f548954b3cd69f176707200d83d460408eadbb7c7b35158
4
- data.tar.gz: fb487bd7275c39da3b3ff34fb4bbb016c77e4666a778c42dd8098c0ef50b3ea5
3
+ metadata.gz: a3fb6617b89131244243bd9fcc7317e6c28266122a75eb01f7e2164cd2d46775
4
+ data.tar.gz: d6241111b4db6cee72273862559d27abd842a83171cd044069ca370c20f3e0e8
5
5
  SHA512:
6
- metadata.gz: 85fe44ebb3c921918bb22148c4d53394d3e5921b1c5b778815bb09120832e7820805555aa68756799a257a05c4fb5efdeb5df53a453009b2333db528fafa5f29
7
- data.tar.gz: 82dc434b862384862420ea07e45d00e2020b5ea20fd7a52ee5196bb5a6786d4c3facd15e64917c0bfd700ac0a1c3aaaa7e761c6970640c60b118f40ca5a1f0e8
6
+ metadata.gz: 7ed67517b5fdf63bd9e5e8e95510d801ea4457ed7fb290777f72d263802b67bd9cf30a4644b99edc6c11571bd93a9b61862e076e2d68fe43973b083d6bab98df
7
+ data.tar.gz: 58f86183335235a8b07cd059fe82e509e5e9701bbbbab02af250598778a720c65e136fb29e505acfe3a68727aeb09ae5e7b4d18cca20b93f67bfd3d940082fb1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## Unreleased
2
+
3
+ * Minimum Ruby version specified at 2.6 [215](https://github.com/alphagov/govspeak/pull/215)
4
+
5
+ ## 6.7.3
6
+
7
+ * Fix regex for footnotes in legislative lists [218](
8
+ https://github.com/alphagov/govspeak/pull/218
9
+
10
+ ## 6.7.2
11
+
12
+ * Fix footnotes in legislative lists [216](https://github.com/alphagov/govspeak/pull/216)
13
+
14
+ ## 6.7.1
15
+
16
+ * Update failing test [212](https://github.com/alphagov/govspeak/pull/212)
17
+ * Fix stats headline HTML semantics [213](https://github.com/alphagov/govspeak/pull/213)
18
+
19
+ ## 6.7.0
20
+
21
+ * Update heading & docs [#206](https://github.com/alphagov/govspeak/pull/206)
22
+
1
23
  ## 6.6.0
2
24
 
3
25
  * Allow passed elements to be relaxed from sanitization [#203](https://github.com/alphagov/govspeak/pull/203)
data/README.md CHANGED
@@ -18,6 +18,23 @@ then create a new document
18
18
  doc = Govspeak::Document.new "^Test^"
19
19
  puts doc.to_html
20
20
 
21
+ ## Changes appearing across GOV.UK
22
+
23
+ Some additional steps or considerations are needed to ensure changes to govspeak cascade across GOV.UK in a holistic way.
24
+
25
+ Once govspeak has been updated and version incremented then:
26
+ - [`govuk_publishing_components` govspeak](https://components.publishing.service.gov.uk/component-guide/govspeak) will also need updating to reflect your most recent change.
27
+ - [Publishing apps](https://docs.publishing.service.gov.uk/apps.html) (including but not limited to [content-publisher](https://github.com/alphagov/content-publisher) & [whitehall](https://github.com/alphagov/whitehall)) also use govspeak, these apps will need to be released with the new govspeak version present.
28
+
29
+ Also, consider if:
30
+ - [whitehall](https://github.com/alphagov/whitehall) needs updating (as custom govspeak changes are present)
31
+ - [govuk-content-schema](https://github.com/alphagov/govuk-content-schemas) needs updating
32
+ - [govpspeak-preview](https://github.com/alphagov/govspeak-preview) is worth updating
33
+
34
+ Any pages that use govspeak to generate Content will need to *republished* in order for the new changes to be reflected.
35
+
36
+ - Data Labs can help identify which pages need updating by [submitting a request](https://gov-uk.atlassian.net/wiki/spaces/GOVUK/pages/1860075525/GOV.UK+Data+Labs#Submitting-a-data-science-request) and [#govuk-2ndline](https://docs.publishing.service.gov.uk/manual/2nd-line.html) can help with republishing
37
+
21
38
  # Extensions
22
39
 
23
40
  In addition to the [standard Markdown syntax](http://daringfireball.net/projects/markdown/syntax "Markdown syntax"), we have added our own extensions.
@@ -106,9 +123,9 @@ Statistic headlines highlight important numbers in content. Displays a statistic
106
123
  Creates the following:
107
124
 
108
125
  ```html
109
- <aside class="stat-headline">
126
+ <div class="stat-headline">
110
127
  <p><em>13.8bn</em> years since the big bang</p>
111
- </aside>
128
+ </div>
112
129
  ```
113
130
 
114
131
  ## Points of Contact
@@ -598,8 +615,8 @@ will output
598
615
  ```html
599
616
  <div id="contact_123" class="contact">
600
617
  <div class="content">
601
- <h3>Government Digital Service</h3>
602
618
  <div class="vcard contact-inner">
619
+ <p>Government Digital Service</p>
603
620
  <div class="email-url-number">
604
621
  <p class="email">
605
622
  <span class="type">Email</span>
@@ -676,4 +693,4 @@ which outputs
676
693
  Start Now
677
694
  <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>
678
695
  </a>
679
- ```
696
+ ```
@@ -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.6.0".freeze
2
+ VERSION = "6.7.3".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"
@@ -185,8 +234,8 @@ module Govspeak
185
234
  end
186
235
 
187
236
  extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) do |body|
188
- %(\n\n<aside class="stat-headline">
189
- #{Govspeak::Document.new(body.strip).to_html}</aside>\n)
237
+ %(\n\n<div class="stat-headline">
238
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
190
239
  end
191
240
 
192
241
  # FIXME: these surrounded_by arguments look dodgy
@@ -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
 
@@ -4,8 +4,8 @@
4
4
  %>
5
5
  <div id="contact_<%= contact.content_id %>" class="<%= ['contact', extra_class].flatten.join(' ') %>">
6
6
  <div class="content">
7
- <h3><%= contact.title %></h3>
8
7
  <div class="vcard contact-inner">
8
+ <p><%= contact.title %></p>
9
9
  <% contact.post_addresses.each do |address| %>
10
10
  <%= Govspeak::HCardPresenter.new(address).render %>
11
11
  <% end %>
@@ -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
@@ -62,8 +62,8 @@ class GovspeakContactsTest < Minitest::Test
62
62
  expected_html_output = %(
63
63
  <div id="contact_4f3383e4-48a2-4461-a41d-f85ea8b89ba0" class="contact postal-address">
64
64
  <div class="content">
65
- <h3>Government Digital Service</h3>
66
65
  <div class="vcard contact-inner">
66
+ <p>Government Digital Service</p>
67
67
  <p class="adr">
68
68
  <span class="street-address">125 Kingsway</span><br>
69
69
  <span class="locality">Holborn</span><br>
@@ -106,8 +106,8 @@ class GovspeakContactsTest < Minitest::Test
106
106
  expected_html_output = %(
107
107
  <div id="contact_4f3383e4-48a2-4461-a41d-f85ea8b89ba0" class="contact">
108
108
  <div class="content">
109
- <h3>Government Digital Service</h3>
110
109
  <div class="vcard contact-inner">
110
+ <p>Government Digital Service</p>
111
111
  <div class="email-url-number">
112
112
  <p class="email">
113
113
  <span class="type">Email</span>
@@ -20,13 +20,13 @@ class GovspeakFootnoteTest < Minitest::Test
20
20
  [^3]: And then they both point here." do
21
21
  assert_html_output(
22
22
  %(
23
- <p>Footnotes can be added<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote">[footnote 1]</a></sup>.</p>
23
+ <p>Footnotes can be added<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>.</p>
24
24
 
25
- <p>Footnotes can be added too<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote">[footnote 2]</a></sup>.</p>
25
+ <p>Footnotes can be added too<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>.</p>
26
26
 
27
- <p>This footnote has a reference number<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote">[footnote 3]</a></sup>.</p>
27
+ <p>This footnote has a reference number<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>.</p>
28
28
 
29
- <p>And this footnote has the same reference number<sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote">[footnote 3]</a></sup>.</p>
29
+ <p>And this footnote has the same reference number<sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>.</p>
30
30
 
31
31
  <div class="footnotes" role="doc-endnotes">
32
32
  <ol>
@@ -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
@@ -30,7 +30,7 @@ class GovspeakTest < Minitest::Test
30
30
 
31
31
  test "stat-headline block extension" do
32
32
  rendered = Govspeak::Document.new("this \n{stat-headline}*13.8bn* Age of the universe in years{/stat-headline}").to_html
33
- assert_equal %(<p>this</p>\n\n<aside class="stat-headline">\n<p><em>13.8bn</em> Age of the universe in years</p>\n</aside>\n), rendered
33
+ assert_equal %(<p>this</p>\n\n<div class="stat-headline">\n<p><em>13.8bn</em> Age of the universe in years</p>\n</div>\n), rendered
34
34
  end
35
35
 
36
36
  test "extracts headers with text, level and generated id" do
@@ -591,6 +591,352 @@ 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]
691
+ * 2. Item 2[^2]
692
+ * 3. Item 3[^3]
693
+ $EndLegislativeList
694
+
695
+ This is a paragraph with a footnote[^4].
696
+
697
+ $LegislativeList
698
+ * 1. Item 1[^5]
699
+ * 2. Item 2[^6]
700
+ * 3. Item 3[^7]
701
+ $EndLegislativeList
702
+
703
+ This is a paragraph with a footnote[^8].
704
+
705
+ $LegislativeList
706
+ * 1. Item 1[^9]
707
+ * 2. Item 2[^10]
708
+ * 3. Item 3[^11]
709
+ $EndLegislativeList
710
+
711
+ This is a paragraph with a footnote[^12].
712
+
713
+ [^1]: Footnote definition 1
714
+ [^2]: Footnote definition 2
715
+ [^3]: Footnote definition 3
716
+ [^4]: Footnote definition 4
717
+ [^5]: Footnote definition 5
718
+ [^6]: Footnote definition 6
719
+ [^7]: Footnote definition 7
720
+ [^8]: Footnote definition 8
721
+ [^9]: Footnote definition 9
722
+ [^10]: Footnote definition 10
723
+ [^11]: Footnote definition 11
724
+ [^12]: Footnote definition 12
725
+ " do
726
+ assert_html_output %(
727
+ <ol class="legislative-list">
728
+ <li>1. Item 1<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>
729
+ </li>
730
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
731
+ </li>
732
+ <li>3. Item 3<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>
733
+ </li>
734
+ </ol>
735
+
736
+ <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>
737
+
738
+ <ol class="legislative-list">
739
+ <li>1. Item 1<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">[footnote 5]</a></sup>
740
+ </li>
741
+ <li>2. Item 2<sup id="fnref:6" role="doc-noteref"><a href="#fn:6" class="footnote" rel="footnote">[footnote 6]</a></sup>
742
+ </li>
743
+ <li>3. Item 3<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote" rel="footnote">[footnote 7]</a></sup>
744
+ </li>
745
+ </ol>
746
+
747
+ <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>
748
+
749
+ <ol class="legislative-list">
750
+ <li>1. Item 1<sup id="fnref:9" role="doc-noteref"><a href="#fn:9" class="footnote" rel="footnote">[footnote 9]</a></sup>
751
+ </li>
752
+ <li>2. Item 2<sup id="fnref:10" role="doc-noteref"><a href="#fn:10" class="footnote" rel="footnote">[footnote 10]</a></sup>
753
+ </li>
754
+ <li>3. Item 3<sup id="fnref:11" role="doc-noteref"><a href="#fn:11" class="footnote" rel="footnote">[footnote 11]</a></sup>
755
+ </li>
756
+ </ol>
757
+
758
+ <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>
759
+
760
+ <div class="footnotes" role="doc-endnotes">
761
+ <ol>
762
+ <li id="fn:1" role="doc-endnote">
763
+ <p>
764
+ Footnote definition 1<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
765
+ </p>
766
+ </li>
767
+ <li id="fn:2" role="doc-endnote">
768
+ <p>
769
+ Footnote definition 2<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
770
+ </p>
771
+ </li>
772
+ <li id="fn:3" role="doc-endnote">
773
+ <p>
774
+ Footnote definition 3<a href="#fnref:3" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
775
+ </p>
776
+ </li>
777
+ <li id="fn:4" role="doc-endnote">
778
+ <p>
779
+ Footnote definition 4<a href="#fnref:4" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
780
+ </p>
781
+ </li>
782
+ <li id="fn:5" role="doc-endnote">
783
+ <p>
784
+ Footnote definition 5<a href="#fnref:5" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
785
+ </p>
786
+ </li>
787
+ <li id="fn:6" role="doc-endnote">
788
+ <p>
789
+ Footnote definition 6<a href="#fnref:6" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
790
+ </p>
791
+ </li>
792
+ <li id="fn:7" role="doc-endnote">
793
+ <p>
794
+ Footnote definition 7<a href="#fnref:7" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
795
+ </p>
796
+ </li>
797
+ <li id="fn:8" role="doc-endnote">
798
+ <p>
799
+ Footnote definition 8<a href="#fnref:8" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
800
+ </p>
801
+ </li>
802
+ <li id="fn:9" role="doc-endnote">
803
+ <p>
804
+ Footnote definition 9<a href="#fnref:9" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
805
+ </p>
806
+ </li>
807
+ <li id="fn:10" role="doc-endnote">
808
+ <p>
809
+ Footnote definition 10<a href="#fnref:10" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
810
+ </p>
811
+ </li>
812
+ <li id="fn:11" role="doc-endnote">
813
+ <p>
814
+ Footnote definition 11<a href="#fnref:11" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
815
+ </p>
816
+ </li>
817
+ <li id="fn:12" role="doc-endnote">
818
+ <p>
819
+ Footnote definition 12<a href="#fnref:12" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
820
+ </p>
821
+ </li>
822
+ </ol>
823
+ </div>
824
+ )
825
+ end
826
+
827
+ test_given_govspeak "
828
+ $LegislativeList
829
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
830
+ * 2. Item 2
831
+ * 3. Item 3
832
+ $EndLegislativeList
833
+
834
+ This is a paragraph with a footnote[^2]
835
+
836
+ [^1]: Footnote definition one
837
+ [^2]: Footnote definition two
838
+ " do
839
+ assert_html_output %(
840
+ <ol class="legislative-list">
841
+ <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>
842
+ </li>
843
+ <li>2. Item 2</li>
844
+ <li>3. Item 3</li>
845
+ </ol>
846
+
847
+ <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>
848
+
849
+ <div class="footnotes" role="doc-endnotes">
850
+ <ol>
851
+ <li id="fn:1" role="doc-endnote">
852
+ <p>
853
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
854
+ </p>
855
+ </li>
856
+ <li id="fn:2" role="doc-endnote">
857
+ <p>
858
+ Footnote definition two<a href="#fnref:2" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
859
+ </p>
860
+ </li>
861
+ </ol>
862
+ </div>
863
+ )
864
+ end
865
+
866
+ test_given_govspeak "
867
+ $LegislativeList
868
+ * 1. Item 1[^1] with a [link](http://www.gov.uk)
869
+ * 2. Item 2
870
+ * 3. Item 3[^2]
871
+ $EndLegislativeList
872
+
873
+ [^1]: Footnote definition one with a [link](http://www.gov.uk) included
874
+ [^2]: Footnote definition two with an external [link](http://www.google.com)
875
+ " do
876
+ assert_html_output %(
877
+ <ol class="legislative-list">
878
+ <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>
879
+ </li>
880
+ <li>2. Item 2</li>
881
+ <li>3. Item 3<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
882
+ </li>
883
+ </ol>
884
+
885
+ <div class="footnotes" role="doc-endnotes">
886
+ <ol>
887
+ <li id="fn:1" role="doc-endnote">
888
+ <p>
889
+ 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>
890
+ </p>
891
+ </li>
892
+ <li id="fn:2" role="doc-endnote">
893
+ <p>
894
+ 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>
895
+ </p>
896
+ </li>
897
+ </ol>
898
+ </div>
899
+ )
900
+ end
901
+
902
+ test_given_govspeak "
903
+ $LegislativeList
904
+ * 1. Item 1[^1] with an ACRONYM
905
+ * 2. Item 2[^2]
906
+ * 3. Item 3
907
+ $EndLegislativeList
908
+
909
+ [^1]: Footnote definition one
910
+ [^2]: Footnote definition two with an ACRONYM
911
+
912
+ *[ACRONYM]: This is the acronym explanation
913
+ " do
914
+ assert_html_output %(
915
+ <ol class="legislative-list">
916
+ <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>
917
+ </li>
918
+ <li>2. Item 2<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>
919
+ </li>
920
+ <li>3. Item 3</li>
921
+ </ol>
922
+
923
+ <div class="footnotes" role="doc-endnotes">
924
+ <ol>
925
+ <li id="fn:1" role="doc-endnote">
926
+ <p>
927
+ Footnote definition one<a href="#fnref:1" class="reversefootnote" role="doc-backlink" aria-label="go to where this is referenced">↩</a>
928
+ </p>
929
+ </li>
930
+ <li id="fn:2" role="doc-endnote">
931
+ <p>
932
+ 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>
933
+ </p>
934
+ </li>
935
+ </ol>
936
+ </div>
937
+ )
938
+ end
939
+
594
940
  test_given_govspeak "
595
941
  The quick brown
596
942
  $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.6.0
4
+ version: 6.7.3
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-01-14 00:00:00.000000000 Z
11
+ date: 2021-09-15 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,14 +360,14 @@ 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