govspeak 6.7.0 → 6.7.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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