govspeak 6.7.0 → 6.7.4

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: 14e93ed0928bdacce945ae5d1ea81d3bbc40508fcc1875c59e02297aed7f78e8
4
- data.tar.gz: b6f7f01034081da748db3d02e81fe31f72f155f2921de02b6d07f65d04587e09
3
+ metadata.gz: 78fc27fd0a2e9e6796195ebd2c5cc4b509d825e8c2d74cf1fb074e2dc13333a4
4
+ data.tar.gz: ea33d0c2b76441a115dc891ffe638745b5afa3366318f9c90d1fb8a7d7649f5f
5
5
  SHA512:
6
- metadata.gz: 00e6e768ecdc8ce782f849957370199bdbfde7a85973c83366590b09155395455f62be45e86bcf8864053070ecb3a9560645bef410e562121ef08acefe2bccac
7
- data.tar.gz: dd68a811064c4e63a092b00ffef191db7f3221308eb84cf916304b8e2207522baea4e37226c09527c4dc25f618b74b2604b39fc96ac986dfbb8008e93454f8fb
6
+ metadata.gz: 25d885461cdf12ffd1e338c1083183d7f5412b3334e3a2fce873234919643452931bb19cbf255abea5e27650a1d28d97d110ff5a43a3e60d22b1624c34e03a5b
7
+ data.tar.gz: 81634215fd9936b191c6e7be565e235ea2aa1a08cf95c326a6bee088faba21ebf7d040886aead25d963430e174db67e7deff6f4aa395ca8e5f58274c6e632c14
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 6.7.4
2
+
3
+ * Remove Nokogumbo dependency to [resolve warning](https://github.com/sparklemotion/nokogiri/issues/2205) [220](https://github.com/alphagov/govspeak/pull/220)
4
+
5
+ ## 6.7.3
6
+
7
+ * Fix regex for footnotes in legislative lists [218](https://github.com/alphagov/govspeak/pull/218)
8
+
9
+ ## 6.7.2
10
+
11
+ * Minimum Ruby version specified at 2.6 [215](https://github.com/alphagov/govspeak/pull/215)
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
+
1
19
  ## 6.7.0
2
20
 
3
21
  * Update heading & docs [#206](https://github.com/alphagov/govspeak/pull/206)
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
@@ -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.7.0".freeze
2
+ VERSION = "6.7.4".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
+ legislative_list_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 legislative_list_footnote_definitions(source)
136
+ is_legislative_list = source.scan(/\$LegislativeList.*?\[\^\d\]*.*?\$EndLegislativeList/m).size.positive?
137
+ footnotes = source.scan(/\[\^(\d+)\]:(.*)/)
138
+ @acronyms = source.scan(/(?<=\*)\[(.*)\]:(.*)/)
139
+
140
+ if is_legislative_list && 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"
@@ -185,8 +233,8 @@ module Govspeak
185
233
  end
186
234
 
187
235
  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)
236
+ %(\n\n<div class="stat-headline">
237
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
190
238
  end
191
239
 
192
240
  # FIXME: these surrounded_by arguments look dodgy
@@ -295,6 +343,18 @@ module Govspeak
295
343
  doc.gsub!("<ul>", "<ol>")
296
344
  doc.gsub!("</ul>", "</ol>")
297
345
  doc.sub!("<ol>", '<ol class="legislative-list">')
346
+
347
+ footnotes = body.scan(/\[\^(\d+)\]/).flatten
348
+
349
+ footnotes.each do |footnote|
350
+ html = "<sup id=\"fnref:#{footnote}\" role=\"doc-noteref\">" \
351
+ "<a href=\"#fn:#{footnote}\" class=\"footnote\" rel=\"footnote\">" \
352
+ "[footnote #{footnote}]</a></sup>"
353
+
354
+ doc.sub!(/(\[\^#{footnote}\])/, html)
355
+ end
356
+
357
+ add_acronym_alt_text(doc) if @acronyms.size.positive?
298
358
  end
299
359
  end
300
360
  end
@@ -386,6 +446,12 @@ module Govspeak
386
446
  def encode(text)
387
447
  HTMLEntities.new.encode(text)
388
448
  end
449
+
450
+ def add_acronym_alt_text(html)
451
+ @acronyms.each do |acronym|
452
+ html.gsub!(acronym[0], "<abbr title=\"#{acronym[1].strip}\">#{acronym[0]}</abbr>")
453
+ end
454
+ end
389
455
  end
390
456
  end
391
457
 
@@ -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
@@ -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.7.0
4
+ version: 6.7.4
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-03-02 00:00:00.000000000 Z
11
+ date: 2021-09-30 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:
375
- - test/govspeak_footnote_test.rb
376
- - test/html_sanitizer_test.rb
377
- - test/govspeak_test.rb
378
355
  - test/test_helper.rb
379
356
  - test/blockquote_extra_quote_remover_test.rb
380
- - test/govspeak_button_test.rb
381
- - test/html_validator_test.rb
357
+ - test/govspeak_images_bang_test.rb
358
+ - test/govspeak_contacts_test.rb
359
+ - test/govspeak_table_with_headers_test.rb
382
360
  - test/govspeak_link_extractor_test.rb
383
- - test/govspeak_attachment_link_test.rb
361
+ - test/govspeak_attachments_image_test.rb
362
+ - test/html_validator_test.rb
363
+ - test/govspeak_button_test.rb
364
+ - test/govspeak_extract_contact_content_ids_test.rb
365
+ - test/govspeak_test_helper.rb
366
+ - test/govspeak_footnote_test.rb
384
367
  - test/govspeak_link_test.rb
385
- - test/govspeak_contacts_test.rb
386
368
  - test/govspeak_structured_headers_test.rb
369
+ - test/html_sanitizer_test.rb
387
370
  - test/govspeak_images_test.rb
388
- - test/govspeak_extract_contact_content_ids_test.rb
389
- - test/govspeak_table_with_headers_test.rb
371
+ - test/govspeak_test.rb
372
+ - test/govspeak_attachment_link_test.rb
390
373
  - test/govspeak_attachment_test.rb
391
- - test/govspeak_attachments_inline_test.rb
392
374
  - test/presenters/h_card_presenter_test.rb
393
- - test/govspeak_test_helper.rb
394
- - test/govspeak_images_bang_test.rb
395
- - test/govspeak_attachments_image_test.rb
375
+ - test/govspeak_attachments_inline_test.rb