govspeak 6.5.9 → 6.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +23 -6
- data/lib/govspeak.rb +8 -4
- data/lib/govspeak/html_sanitizer.rb +5 -4
- data/lib/govspeak/version.rb +1 -1
- data/lib/templates/contact.html.erb +1 -1
- data/test/govspeak_contacts_test.rb +2 -2
- data/test/govspeak_footnote_test.rb +4 -4
- data/test/govspeak_test.rb +25 -1
- data/test/html_sanitizer_test.rb +6 -0
- metadata +8 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b07175e22a88ddf687631c2a157d00f9649efc118ab3e535d95cbda00918d43
|
4
|
+
data.tar.gz: 430f7d18852c8fdd549812c0260b118108292f34f2767902217c9d57a80d1f8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
<
|
126
|
+
<div class="stat-headline">
|
110
127
|
<p><em>13.8bn</em> years since the big bang</p>
|
111
|
-
</
|
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<
|
188
|
-
#{Govspeak::Document.new(body.strip).to_html}</
|
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
|
-
|
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],
|
data/lib/govspeak/version.rb
CHANGED
@@ -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>
|
data/test/govspeak_test.rb
CHANGED
@@ -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<
|
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?
|
data/test/html_sanitizer_test.rb
CHANGED
@@ -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.
|
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:
|
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
|
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
|
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
|
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
|
184
|
+
version: '5.14'
|
191
185
|
- !ruby/object:Gem::Dependency
|
192
186
|
name: pry-byebug
|
193
187
|
requirement: !ruby/object:Gem::Requirement
|