govspeak 8.3.0 → 8.3.2

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: 92a47d834646bd30072105c15ed418c6fbd09ad18c5469928be7d76a6cdf8d97
4
- data.tar.gz: 94a44d03aa697a24937596786e8dff07da213ad085ca39ce52394cb040c3c7d1
3
+ metadata.gz: 5a58c52e5a9797911c326259920750977c19b81068825b6b947728fe6af410de
4
+ data.tar.gz: de9ac98e971c04c0ac4cc6d7e8f1cc987b2a5310ce2efb5bae4aa2b6ec5ccdc0
5
5
  SHA512:
6
- metadata.gz: b0e59b5d11641d737428bc419c77c749300115625442fb44b0eba026e1b3755e648a1a14ff5199c004ef18cdc72a66953f3c90feb883592dfd8e86719536068c
7
- data.tar.gz: 3ab9bb92193243b5c0b0920260c7ae23773495d3683df54197775aef23337d743edc091a6068291d744fee7010142650e3896a6735310e7456227ab7e587465d
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))
@@ -1,3 +1,3 @@
1
1
  module Govspeak
2
- VERSION = "8.3.0".freeze
2
+ VERSION = "8.3.2".freeze
3
3
  end
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
- {::options parse_block_html=\"true\" /}
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 control flow in `parse_block_html` and
304
- # maintain the same functionality as a previous version of this extension.
300
+ # The surrounding div is neccessary to accurately identify legislative lists
301
+ # in post-processing.
305
302
  <<~BODY
306
- {::options parse_block_html=\"true\" ordered_lists_disabled=\"true\" /}
307
- <div class="legislative-list-wrapper">#{body}</div>
308
- {::options parse_block_html=\"false\" ordered_lists_disabled=\"false\" /}
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
- # Kramdown loads parsers into the instance from `options` which are scoped to
59
- # the class. Because we are changing these options inside an instance, we must
60
- # reconfigure the parser before and after disbaling ordered lists.
61
- Govspeak::KramdownOverrides.with_kramdown_ordered_lists_disabled do
62
- configure_parser
63
- super
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
- configure_parser
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(
@@ -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.0
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-10-12 00:00:00.000000000 Z
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.20
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