govspeak 8.3.0 → 8.3.2
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/govspeak/version.rb +1 -1
- data/lib/govspeak.rb +6 -9
- data/lib/kramdown/parser/govuk.rb +101 -7
- data/test/govspeak_images_test.rb +0 -7
- data/test/govspeak_test.rb +36 -0
- data/test/govspeak_test_helper.rb +7 -0
- metadata +3 -4
- data/lib/govspeak/kramdown_overrides.rb +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a58c52e5a9797911c326259920750977c19b81068825b6b947728fe6af410de
|
|
4
|
+
data.tar.gz: de9ac98e971c04c0ac4cc6d7e8f1cc987b2a5310ce2efb5bae4aa2b6ec5ccdc0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21b984b959a200d44869aad30b0d4db910feba0985d701b918152df0fb507cc46710ce0ee9c661f32e93686955f6c2aa722abeb2e95a96527cf3122d53742497
|
|
7
|
+
data.tar.gz: b33b3accc379b22a62a3354d041b943fdde26a5a3bc040308008d1eb1ebcd2d63b27d18d12a40a774b30b1052ef6b9741f733c6b9f5e3ab495831c305df233f5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 8.3.2
|
|
2
|
+
|
|
3
|
+
* Various bug fixes related to legislative list components ([#298](https://github.com/alphagov/govspeak/pull/298))
|
|
4
|
+
|
|
5
|
+
## 8.3.1
|
|
6
|
+
|
|
7
|
+
* Bug fixes related to block elements in call to action and legislative list components ([#293](https://github.com/alphagov/govspeak/pull/293))
|
|
8
|
+
|
|
1
9
|
## 8.3.0
|
|
2
10
|
|
|
3
11
|
* Various bug fixes related to abbreviations in call to action and legislative list components ([#291](https://github.com/alphagov/govspeak/pull/291))
|
data/lib/govspeak/version.rb
CHANGED
data/lib/govspeak.rb
CHANGED
|
@@ -13,7 +13,6 @@ require "govspeak/header_extractor"
|
|
|
13
13
|
require "govspeak/structured_header_extractor"
|
|
14
14
|
require "govspeak/html_validator"
|
|
15
15
|
require "govspeak/html_sanitizer"
|
|
16
|
-
require "govspeak/kramdown_overrides"
|
|
17
16
|
require "govspeak/blockquote_extra_quote_remover"
|
|
18
17
|
require "govspeak/post_processor"
|
|
19
18
|
require "govspeak/link_extractor"
|
|
@@ -278,9 +277,7 @@ module Govspeak
|
|
|
278
277
|
|
|
279
278
|
extension("call-to-action", surrounded_by("$CTA")) do |body|
|
|
280
279
|
<<~BODY
|
|
281
|
-
|
|
282
|
-
<div class="call-to-action">#{body}</div>
|
|
283
|
-
{::options parse_block_html=\"false\" /}
|
|
280
|
+
<div class="call-to-action" markdown="1">#{body}</div>
|
|
284
281
|
BODY
|
|
285
282
|
end
|
|
286
283
|
|
|
@@ -300,12 +297,12 @@ module Govspeak
|
|
|
300
297
|
end
|
|
301
298
|
|
|
302
299
|
extension("legislative list", /#{NEW_PARAGRAPH_LOOKBEHIND}\$LegislativeList\s*$(.*?)\$EndLegislativeList/m) do |body|
|
|
303
|
-
# The surrounding div is neccessary to
|
|
304
|
-
#
|
|
300
|
+
# The surrounding div is neccessary to accurately identify legislative lists
|
|
301
|
+
# in post-processing.
|
|
305
302
|
<<~BODY
|
|
306
|
-
{::options
|
|
307
|
-
<div class="legislative-list-wrapper">#{body}</div>
|
|
308
|
-
{::options
|
|
303
|
+
{::options ordered_lists_disabled=\"true\" /}
|
|
304
|
+
<div class="legislative-list-wrapper" markdown="1">#{body}</div>
|
|
305
|
+
{::options ordered_lists_disabled=\"false\" /}
|
|
309
306
|
BODY
|
|
310
307
|
end
|
|
311
308
|
|
|
@@ -53,17 +53,111 @@ module Kramdown
|
|
|
53
53
|
def parse_block_html
|
|
54
54
|
return false if CUSTOM_INLINE_ELEMENTS.include?(@src[1].downcase)
|
|
55
55
|
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# We override the parse_list method with a modified version where ordered lists are
|
|
60
|
+
# disabled (for use with legislative lists). The majority of the method body is copied
|
|
61
|
+
# over (from https://github.com/gettalong/kramdown/blob/REL_2_3_1/lib/kramdown/parser/kramdown/list.rb#L54),
|
|
62
|
+
# only the LIST_START is changed. Previously, we dynamically modified some of the
|
|
63
|
+
# class-scoped variables used in this method; this provides a thread-safe alternative.
|
|
64
|
+
def parse_list
|
|
56
65
|
return super unless @options[:ordered_lists_disabled]
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
return if @src.check(LIST_START_OL)
|
|
68
|
+
|
|
69
|
+
start_line_number = @src.current_line_number
|
|
70
|
+
type, list_start_re = (@src.check(LIST_START_UL) ? [:ul, LIST_START_UL] : [:ol, LIST_START_OL])
|
|
71
|
+
list = new_block_el(type, nil, nil, location: start_line_number)
|
|
72
|
+
|
|
73
|
+
item = nil
|
|
74
|
+
content_re, lazy_re, indent_re = nil
|
|
75
|
+
eob_found = false
|
|
76
|
+
nested_list_found = false
|
|
77
|
+
last_is_blank = false
|
|
78
|
+
until @src.eos?
|
|
79
|
+
start_line_number = @src.current_line_number
|
|
80
|
+
if last_is_blank && @src.check(HR_START)
|
|
81
|
+
break
|
|
82
|
+
elsif @src.scan(EOB_MARKER)
|
|
83
|
+
eob_found = true
|
|
84
|
+
break
|
|
85
|
+
elsif @src.scan(list_start_re)
|
|
86
|
+
list.options[:first_list_marker] ||= @src[1].strip
|
|
87
|
+
item = Element.new(:li, nil, nil, location: start_line_number)
|
|
88
|
+
item.value, indentation, content_re, lazy_re, indent_re =
|
|
89
|
+
parse_first_list_line(@src[1].length, @src[2])
|
|
90
|
+
list.children << item
|
|
91
|
+
|
|
92
|
+
item.value.sub!(self.class::LIST_ITEM_IAL) do
|
|
93
|
+
parse_attribute_list(::Regexp.last_match(1), item.options[:ial] ||= {})
|
|
94
|
+
""
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
list_start_re = fetch_pattern(type, indentation)
|
|
98
|
+
nested_list_found = (item.value =~ LIST_START_UL)
|
|
99
|
+
last_is_blank = false
|
|
100
|
+
item.value = [item.value]
|
|
101
|
+
elsif (result = @src.scan(content_re)) || (!last_is_blank && (result = @src.scan(lazy_re)))
|
|
102
|
+
result.sub!(/^(\t+)/) { " " * 4 * ::Regexp.last_match(1).length }
|
|
103
|
+
indentation_found = result.sub!(indent_re, "")
|
|
104
|
+
if !nested_list_found && indentation_found && result =~ LIST_START_UL
|
|
105
|
+
item.value << +""
|
|
106
|
+
nested_list_found = true
|
|
107
|
+
elsif nested_list_found && !indentation_found && result =~ LIST_START_UL
|
|
108
|
+
result = " " * (indentation + 4) << result
|
|
109
|
+
end
|
|
110
|
+
item.value.last << result
|
|
111
|
+
last_is_blank = false
|
|
112
|
+
elsif (result = @src.scan(BLANK_LINE))
|
|
113
|
+
nested_list_found = true
|
|
114
|
+
last_is_blank = true
|
|
115
|
+
item.value.last << result
|
|
116
|
+
else
|
|
117
|
+
break
|
|
118
|
+
end
|
|
64
119
|
end
|
|
65
120
|
|
|
66
|
-
|
|
121
|
+
@tree.children << list
|
|
122
|
+
|
|
123
|
+
last = nil
|
|
124
|
+
list.children.each do |it|
|
|
125
|
+
temp = Element.new(:temp, nil, nil, location: it.options[:location])
|
|
126
|
+
|
|
127
|
+
env = save_env
|
|
128
|
+
location = it.options[:location]
|
|
129
|
+
it.value.each do |val|
|
|
130
|
+
@src = ::Kramdown::Utils::StringScanner.new(val, location)
|
|
131
|
+
parse_blocks(temp)
|
|
132
|
+
location = @src.current_line_number
|
|
133
|
+
end
|
|
134
|
+
restore_env(env)
|
|
135
|
+
|
|
136
|
+
it.children = temp.children
|
|
137
|
+
it.value = nil
|
|
138
|
+
|
|
139
|
+
it_children = it.children
|
|
140
|
+
next if it_children.empty?
|
|
141
|
+
|
|
142
|
+
# Handle the case where an EOB marker is inserted by a block IAL for the first paragraph
|
|
143
|
+
it_children.delete_at(1) if it_children.first.type == :p &&
|
|
144
|
+
it_children.length >= 2 && it_children[1].type == :eob && it_children.first.options[:ial]
|
|
145
|
+
|
|
146
|
+
if it_children.first.type == :p &&
|
|
147
|
+
(it_children.length < 2 || it_children[1].type != :blank ||
|
|
148
|
+
(it == list.children.last && it_children.length == 2 && !eob_found)) &&
|
|
149
|
+
(list.children.last != it || list.children.size == 1 ||
|
|
150
|
+
list.children[0..-2].any? { |cit| !cit.children.first || cit.children.first.type != :p || cit.children.first.options[:transparent] })
|
|
151
|
+
it_children.first.children.first.value << "\n" if it_children.size > 1 && it_children[1].type != :blank
|
|
152
|
+
it_children.first.options[:transparent] = true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
last = (it_children.last.type == :blank ? it_children.pop : nil)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
@tree.children << last if !last.nil? && !eob_found
|
|
159
|
+
|
|
160
|
+
true
|
|
67
161
|
end
|
|
68
162
|
end
|
|
69
163
|
end
|
|
@@ -4,13 +4,6 @@ require "govspeak_test_helper"
|
|
|
4
4
|
class GovspeakImagesTest < Minitest::Test
|
|
5
5
|
include GovspeakTestHelper
|
|
6
6
|
|
|
7
|
-
def build_image(attrs = {})
|
|
8
|
-
attrs[:alt_text] ||= "my alt"
|
|
9
|
-
attrs[:url] ||= "http://example.com/image.jpg"
|
|
10
|
-
attrs[:id] ||= "image-id"
|
|
11
|
-
attrs
|
|
12
|
-
end
|
|
13
|
-
|
|
14
7
|
test "Image:image-id syntax renders an image in options[:images]" do
|
|
15
8
|
given_govspeak "[Image:image-id]", images: [build_image] do
|
|
16
9
|
assert_html_output(
|
data/test/govspeak_test.rb
CHANGED
|
@@ -683,6 +683,24 @@ Teston
|
|
|
683
683
|
)
|
|
684
684
|
end
|
|
685
685
|
|
|
686
|
+
test "CTA with image" do
|
|
687
|
+
given_govspeak "
|
|
688
|
+
$CTA
|
|
689
|
+
[Image:image-id]
|
|
690
|
+
$CTA
|
|
691
|
+
|
|
692
|
+
Some text
|
|
693
|
+
", images: [build_image] do
|
|
694
|
+
assert_html_output %(
|
|
695
|
+
<div class="call-to-action">
|
|
696
|
+
<figure class="image embedded"><div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div></figure>
|
|
697
|
+
</div>
|
|
698
|
+
|
|
699
|
+
<p>Some text</p>
|
|
700
|
+
)
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
686
704
|
test_given_govspeak "
|
|
687
705
|
1. rod
|
|
688
706
|
2. jane
|
|
@@ -1268,6 +1286,24 @@ Teston
|
|
|
1268
1286
|
)
|
|
1269
1287
|
end
|
|
1270
1288
|
|
|
1289
|
+
test "LegislativeList with image" do
|
|
1290
|
+
given_govspeak "
|
|
1291
|
+
$LegislativeList
|
|
1292
|
+
[Image:image-id]
|
|
1293
|
+
$EndLegislativeList
|
|
1294
|
+
|
|
1295
|
+
Some text
|
|
1296
|
+
", images: [build_image] do
|
|
1297
|
+
assert_html_output %(
|
|
1298
|
+
<div class="legislative-list-wrapper">
|
|
1299
|
+
<figure class="image embedded"><div class="img"><img src="http://example.com/image.jpg" alt="my alt"></div></figure>
|
|
1300
|
+
</div>
|
|
1301
|
+
|
|
1302
|
+
<p>Some text</p>
|
|
1303
|
+
)
|
|
1304
|
+
end
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1271
1307
|
test_given_govspeak "
|
|
1272
1308
|
Zippy, Bungle and George did not qualify for the tax exemption in s428. They filled in their tax return accordingly.
|
|
1273
1309
|
" do
|
|
@@ -73,6 +73,13 @@ module GovspeakTestHelper
|
|
|
73
73
|
coder.decode(html)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
def build_image(attrs = {})
|
|
77
|
+
attrs[:alt_text] ||= "my alt"
|
|
78
|
+
attrs[:url] ||= "http://example.com/image.jpg"
|
|
79
|
+
attrs[:id] ||= "image-id"
|
|
80
|
+
attrs
|
|
81
|
+
end
|
|
82
|
+
|
|
76
83
|
module ClassMethods
|
|
77
84
|
def test_given_govspeak(govspeak, options = {}, &block)
|
|
78
85
|
test "Given #{govspeak}" do
|
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: 8.3.
|
|
4
|
+
version: 8.3.2
|
|
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: 2023-
|
|
11
|
+
date: 2023-12-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: actionview
|
|
@@ -235,7 +235,6 @@ files:
|
|
|
235
235
|
- lib/govspeak/header_extractor.rb
|
|
236
236
|
- lib/govspeak/html_sanitizer.rb
|
|
237
237
|
- lib/govspeak/html_validator.rb
|
|
238
|
-
- lib/govspeak/kramdown_overrides.rb
|
|
239
238
|
- lib/govspeak/link_extractor.rb
|
|
240
239
|
- lib/govspeak/post_processor.rb
|
|
241
240
|
- lib/govspeak/presenters/attachment_image_presenter.rb
|
|
@@ -327,7 +326,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
327
326
|
- !ruby/object:Gem::Version
|
|
328
327
|
version: '0'
|
|
329
328
|
requirements: []
|
|
330
|
-
rubygems_version: 3.4.
|
|
329
|
+
rubygems_version: 3.4.22
|
|
331
330
|
signing_key:
|
|
332
331
|
specification_version: 4
|
|
333
332
|
summary: Markup language for single domain
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
module Govspeak
|
|
2
|
-
module KramdownOverrides
|
|
3
|
-
# This depends on two internal parts of Kramdown.
|
|
4
|
-
# 1. Parser registry (kramdown/parser/kramdown.rb#define_parser)
|
|
5
|
-
# 2. Kramdown list regexes (kramdown/parser/kramdown/list.rb)
|
|
6
|
-
# Updating the Kramdown gem therefore also means updating this file to to
|
|
7
|
-
# match Kramdown's internals.
|
|
8
|
-
|
|
9
|
-
def self.with_kramdown_ordered_lists_disabled
|
|
10
|
-
original_list_start = list_start
|
|
11
|
-
redefine_kramdown_const(:LIST_START, list_start_ul)
|
|
12
|
-
list_parser = kramdown_parsers.delete(:list)
|
|
13
|
-
Kramdown::Parser::Kramdown.define_parser(:list, list_start_ul)
|
|
14
|
-
|
|
15
|
-
yield
|
|
16
|
-
ensure
|
|
17
|
-
redefine_kramdown_const(:LIST_START, original_list_start)
|
|
18
|
-
kramdown_parsers[:list] = list_parser
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.list_start
|
|
22
|
-
Kramdown::Parser::Kramdown::LIST_START
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.list_start_ul
|
|
26
|
-
Kramdown::Parser::Kramdown::LIST_START_UL
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.kramdown_parsers
|
|
30
|
-
Kramdown::Parser::Kramdown.class_variable_get("@@parsers")
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def self.redefine_kramdown_const(const, value)
|
|
34
|
-
Kramdown::Parser::Kramdown.send(:remove_const, const)
|
|
35
|
-
Kramdown::Parser::Kramdown.send(:const_set, const, value)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|