govspeak 6.5.9 → 6.7.1

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: 948aced50c3d3842255ea4206a651229de59b2beef42e0c50e55e204354d9b5f
4
- data.tar.gz: cc55abe4b54b112a3aa1cb350a94270b11b9f0c11a5ca71479f55bb0efbf657d
3
+ metadata.gz: 3b07175e22a88ddf687631c2a157d00f9649efc118ab3e535d95cbda00918d43
4
+ data.tar.gz: 430f7d18852c8fdd549812c0260b118108292f34f2767902217c9d57a80d1f8b
5
5
  SHA512:
6
- metadata.gz: 1e0c1b0d6ca1fe4999e4135536328ecdc60bd34f368d986a808cee6de687f58198a080c19beffd47df6d80130edd2010eb1a09ccd840ea8adb9375c0b747e533
7
- data.tar.gz: e47aeeabecc4ffccff7342d1a1ad2e1ddd6cd8aabf5850f740fa3bf5ecdd9395bbded84222d55a5c8998748d7491a649793c550ab49564cd098486623684b275
6
+ metadata.gz: 0fd6c1d0b6e8a416fdeb6d7aba99868dfb8e9ccf80191666dc771dcdf56a9bf396297569759c172608c31daf7bf75a891914e98713fc0e99b8458220b3dd7934
7
+ data.tar.gz: 8a04ab8364ea6ac989b4a1549ce8c4f152ad57988144183f7db00b5b256fce4b5823d79ac611a4078f75ccee5bd1d42f5a81344140979d2066916c2693a35dc4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## Unreleased
2
+
3
+ ## 6.7.1
4
+
5
+ * Update failing test [212](https://github.com/alphagov/govspeak/pull/212)
6
+ * Fix stats headline HTML semantics [213](https://github.com/alphagov/govspeak/pull/213)
7
+
8
+ ## 6.7.0
9
+
10
+ * Update heading & docs [#206](https://github.com/alphagov/govspeak/pull/206)
11
+
12
+ ## 6.6.0
13
+
14
+ * Allow passed elements to be relaxed from sanitization [#203](https://github.com/alphagov/govspeak/pull/203)
15
+
16
+ ## 6.5.11
17
+
18
+ * Fix issue rendering $CTA blocks before $C (PR#202)
19
+
20
+ ## 6.5.10
21
+
22
+ * Be optimistic in versions of govuk_publishing_components and i18n allowed (PR#200)
23
+
1
24
  ## 6.5.9
2
25
 
3
26
  * Adjust footnote markup to accommodate multiple references (PR#198)
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.
@@ -65,7 +82,7 @@ creates an example box
65
82
 
66
83
  ## Highlights
67
84
 
68
- ### Advisory
85
+ ### Advisory (DEPRECATED: marked for removal. Use 'Information callouts' instead.)
69
86
 
70
87
  @This is a very important message or warning@
71
88
 
@@ -77,7 +94,7 @@ highlights the enclosed text in yellow
77
94
  </h3>
78
95
  ```
79
96
 
80
- ### Answer
97
+ ### Answer (DEPRECATED: marked for removal)
81
98
 
82
99
  {::highlight-answer}
83
100
  The VAT rate is *20%*
@@ -106,9 +123,9 @@ Statistic headlines highlight important numbers in content. Displays a statistic
106
123
  Creates the following:
107
124
 
108
125
  ```html
109
- <aside class="stat-headline">
126
+ <div class="stat-headline">
110
127
  <p><em>13.8bn</em> years since the big bang</p>
111
- </aside>
128
+ </div>
112
129
  ```
113
130
 
114
131
  ## Points of Contact
@@ -598,8 +615,8 @@ will output
598
615
  ```html
599
616
  <div id="contact_123" class="contact">
600
617
  <div class="content">
601
- <h3>Government Digital Service</h3>
602
618
  <div class="vcard contact-inner">
619
+ <p>Government Digital Service</p>
603
620
  <div class="email-url-number">
604
621
  <p class="email">
605
622
  <span class="type">Email</span>
@@ -676,4 +693,4 @@ which outputs
676
693
  Start Now
677
694
  <svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" role="presentation" focusable="false"><path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path></svg>
678
695
  </a>
679
- ```
696
+ ```
data/lib/govspeak.rb CHANGED
@@ -53,6 +53,7 @@ module Govspeak
53
53
  @source = source ? source.dup : ""
54
54
 
55
55
  @images = options.delete(:images) || []
56
+ @allowed_elements = options.delete(:allowed_elements) || []
56
57
  @attachments = Array.wrap(options.delete(:attachments))
57
58
  @links = Array.wrap(options.delete(:links))
58
59
  @contacts = Array.wrap(options.delete(:contacts))
@@ -66,7 +67,7 @@ module Govspeak
66
67
  def to_html
67
68
  @to_html ||= begin
68
69
  html = if @options[:sanitize]
69
- HtmlSanitizer.new(kramdown_doc.to_html).sanitize
70
+ HtmlSanitizer.new(kramdown_doc.to_html).sanitize(allowed_elements: @allowed_elements)
70
71
  else
71
72
  kramdown_doc.to_html
72
73
  end
@@ -184,8 +185,8 @@ module Govspeak
184
185
  end
185
186
 
186
187
  extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m) do |body|
187
- %(\n\n<aside class="stat-headline">
188
- #{Govspeak::Document.new(body.strip).to_html}</aside>\n)
188
+ %(\n\n<div class="stat-headline">
189
+ #{Govspeak::Document.new(body.strip).to_html}</div>\n)
189
190
  end
190
191
 
191
192
  # FIXME: these surrounded_by arguments look dodgy
@@ -272,6 +273,10 @@ module Govspeak
272
273
  lines.join
273
274
  end
274
275
 
276
+ # More specific tags must be defined first. Those defined earlier have a
277
+ # higher precedence for being matched. For example $CTA must be defined
278
+ # before $C otherwise the first ($C)TA fill be matched to a contact tag.
279
+ wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
275
280
  wrap_with_div("summary", "$!")
276
281
  wrap_with_div("form-download", "$D")
277
282
  wrap_with_div("contact", "$C")
@@ -279,7 +284,6 @@ module Govspeak
279
284
  wrap_with_div("information", "$I", Govspeak::Document)
280
285
  wrap_with_div("additional-information", "$AI")
281
286
  wrap_with_div("example", "$E", Govspeak::Document)
282
- wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
283
287
 
284
288
  extension("address", surrounded_by("$A")) do |body|
285
289
  %(\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n)
@@ -40,18 +40,19 @@ class Govspeak::HtmlSanitizer
40
40
  @allowed_image_hosts = options[:allowed_image_hosts]
41
41
  end
42
42
 
43
- def sanitize
43
+ def sanitize(allowed_elements: [])
44
44
  transformers = [TableCellTextAlignWhitelister.new]
45
45
  if @allowed_image_hosts && @allowed_image_hosts.any?
46
46
  transformers << ImageSourceWhitelister.new(@allowed_image_hosts)
47
47
  end
48
- Sanitize.clean(@dirty_html, Sanitize::Config.merge(sanitize_config, transformers: transformers))
48
+
49
+ Sanitize.clean(@dirty_html, Sanitize::Config.merge(sanitize_config(allowed_elements: allowed_elements), transformers: transformers))
49
50
  end
50
51
 
51
- def sanitize_config
52
+ def sanitize_config(allowed_elements: [])
52
53
  Sanitize::Config.merge(
53
54
  Sanitize::Config::RELAXED,
54
- elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment govspeak-embed-attachment-link svg path],
55
+ elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment govspeak-embed-attachment-link svg path].concat(allowed_elements),
55
56
  attributes: {
56
57
  :all => Sanitize::Config::RELAXED[:attributes][:all] + %w[role aria-label],
57
58
  "a" => Sanitize::Config::RELAXED[:attributes]["a"] + [:data],
@@ -1,3 +1,3 @@
1
1
  module Govspeak
2
- VERSION = "6.5.9".freeze
2
+ VERSION = "6.7.1".freeze
3
3
  end
@@ -4,8 +4,8 @@
4
4
  %>
5
5
  <div id="contact_<%= contact.content_id %>" class="<%= ['contact', extra_class].flatten.join(' ') %>">
6
6
  <div class="content">
7
- <h3><%= contact.title %></h3>
8
7
  <div class="vcard contact-inner">
8
+ <p><%= contact.title %></p>
9
9
  <% contact.post_addresses.each do |address| %>
10
10
  <%= Govspeak::HCardPresenter.new(address).render %>
11
11
  <% end %>
@@ -62,8 +62,8 @@ class GovspeakContactsTest < Minitest::Test
62
62
  expected_html_output = %(
63
63
  <div id="contact_4f3383e4-48a2-4461-a41d-f85ea8b89ba0" class="contact postal-address">
64
64
  <div class="content">
65
- <h3>Government Digital Service</h3>
66
65
  <div class="vcard contact-inner">
66
+ <p>Government Digital Service</p>
67
67
  <p class="adr">
68
68
  <span class="street-address">125 Kingsway</span><br>
69
69
  <span class="locality">Holborn</span><br>
@@ -106,8 +106,8 @@ class GovspeakContactsTest < Minitest::Test
106
106
  expected_html_output = %(
107
107
  <div id="contact_4f3383e4-48a2-4461-a41d-f85ea8b89ba0" class="contact">
108
108
  <div class="content">
109
- <h3>Government Digital Service</h3>
110
109
  <div class="vcard contact-inner">
110
+ <p>Government Digital Service</p>
111
111
  <div class="email-url-number">
112
112
  <p class="email">
113
113
  <span class="type">Email</span>
@@ -20,13 +20,13 @@ class GovspeakFootnoteTest < Minitest::Test
20
20
  [^3]: And then they both point here." do
21
21
  assert_html_output(
22
22
  %(
23
- <p>Footnotes can be added<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote">[footnote 1]</a></sup>.</p>
23
+ <p>Footnotes can be added<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">[footnote 1]</a></sup>.</p>
24
24
 
25
- <p>Footnotes can be added too<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote">[footnote 2]</a></sup>.</p>
25
+ <p>Footnotes can be added too<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">[footnote 2]</a></sup>.</p>
26
26
 
27
- <p>This footnote has a reference number<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote">[footnote 3]</a></sup>.</p>
27
+ <p>This footnote has a reference number<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>.</p>
28
28
 
29
- <p>And this footnote has the same reference number<sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote">[footnote 3]</a></sup>.</p>
29
+ <p>And this footnote has the same reference number<sup id="fnref:3:1" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">[footnote 3]</a></sup>.</p>
30
30
 
31
31
  <div class="footnotes" role="doc-endnotes">
32
32
  <ol>
@@ -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
@@ -440,6 +440,25 @@ Teston
440
440
  </div>)
441
441
  end
442
442
 
443
+ test_given_govspeak "
444
+ $CTA
445
+ Click here to start the tool
446
+ $CTA
447
+
448
+ $C
449
+ Here is some text
450
+ $C
451
+ " do
452
+ assert_html_output %(
453
+ <div class="call-to-action">
454
+ <p>Click here to start the tool</p>
455
+ </div>
456
+
457
+ <div class="contact">
458
+ <p>Here is some text</p>
459
+ </div>)
460
+ end
461
+
443
462
  test_given_govspeak "
444
463
  [internal link](http://www.not-external.com)
445
464
 
@@ -647,6 +666,11 @@ Teston
647
666
  assert_equal "<script>doGoodThings();</script>", document.to_html.strip
648
667
  end
649
668
 
669
+ test "it can exclude stipulated elements from sanitization" do
670
+ document = Govspeak::Document.new("<uncommon-element>some content</uncommon-element>", allowed_elements: %w[uncommon-element])
671
+ assert_equal "<uncommon-element>some content</uncommon-element>", document.to_html.strip
672
+ end
673
+
650
674
  test "identifies a Govspeak document containing malicious HTML as invalid" do
651
675
  document = Govspeak::Document.new("<script>doBadThings();</script>")
652
676
  refute document.valid?
@@ -96,4 +96,10 @@ class HtmlSanitizerTest < Minitest::Test
96
96
  assert_equal "<table><thead><tr><th>thing</th></tr></thead><tbody><tr><td>thing</td></tr></tbody></table>", Govspeak::HtmlSanitizer.new(html).sanitize
97
97
  end
98
98
  end
99
+
100
+ test "excludes specified elements from sanitization" do
101
+ html = "<custom-allowed-element><p>text</p></custom-allowed-element>"
102
+ assert_equal "<p>text</p>", Govspeak::HtmlSanitizer.new(html).sanitize
103
+ assert_equal html, Govspeak::HtmlSanitizer.new(html).sanitize(allowed_elements: %w[custom-allowed-element])
104
+ end
99
105
  end
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.5.9
4
+ version: 6.7.1
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: 2020-11-09 00:00:00.000000000 Z
11
+ date: 2021-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -56,20 +56,14 @@ dependencies:
56
56
  requirements:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
- version: '23.0'
60
- - - "<"
61
- - !ruby/object:Gem::Version
62
- version: '23.4'
59
+ version: '23'
63
60
  type: :runtime
64
61
  prerelease: false
65
62
  version_requirements: !ruby/object:Gem::Requirement
66
63
  requirements:
67
64
  - - ">="
68
65
  - !ruby/object:Gem::Version
69
- version: '23.0'
70
- - - "<"
71
- - !ruby/object:Gem::Version
72
- version: '23.4'
66
+ version: '23'
73
67
  - !ruby/object:Gem::Dependency
74
68
  name: htmlentities
75
69
  requirement: !ruby/object:Gem::Requirement
@@ -88,14 +82,14 @@ dependencies:
88
82
  name: i18n
89
83
  requirement: !ruby/object:Gem::Requirement
90
84
  requirements:
91
- - - "~>"
85
+ - - ">="
92
86
  - !ruby/object:Gem::Version
93
87
  version: '0.7'
94
88
  type: :runtime
95
89
  prerelease: false
96
90
  version_requirements: !ruby/object:Gem::Requirement
97
91
  requirements:
98
- - - "~>"
92
+ - - ">="
99
93
  - !ruby/object:Gem::Version
100
94
  version: '0.7'
101
95
  - !ruby/object:Gem::Dependency
@@ -180,14 +174,14 @@ dependencies:
180
174
  requirements:
181
175
  - - "~>"
182
176
  - !ruby/object:Gem::Version
183
- version: 5.14.1
177
+ version: '5.14'
184
178
  type: :development
185
179
  prerelease: false
186
180
  version_requirements: !ruby/object:Gem::Requirement
187
181
  requirements:
188
182
  - - "~>"
189
183
  - !ruby/object:Gem::Version
190
- version: 5.14.1
184
+ version: '5.14'
191
185
  - !ruby/object:Gem::Dependency
192
186
  name: pry-byebug
193
187
  requirement: !ruby/object:Gem::Requirement