govspeak 6.5.3 → 6.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/Rakefile +6 -3
- data/lib/govspeak.rb +54 -52
- data/lib/govspeak/html_sanitizer.rb +3 -3
- data/lib/govspeak/kramdown_overrides.rb +2 -2
- data/lib/govspeak/link_extractor.rb +3 -3
- data/lib/govspeak/post_processor.rb +17 -5
- data/lib/govspeak/presenters/attachment_presenter.rb +26 -26
- data/lib/govspeak/presenters/image_presenter.rb +2 -2
- data/lib/govspeak/structured_header_extractor.rb +2 -2
- data/lib/govspeak/version.rb +1 -1
- data/lib/kramdown/parser/govuk.rb +4 -5
- data/test/blockquote_extra_quote_remover_test.rb +25 -27
- data/test/govspeak_attachment_link_test.rb +0 -2
- data/test/govspeak_attachment_test.rb +0 -2
- data/test/govspeak_attachments_image_test.rb +2 -4
- data/test/govspeak_attachments_inline_test.rb +4 -6
- data/test/govspeak_button_test.rb +8 -10
- data/test/govspeak_contacts_test.rb +11 -13
- data/test/govspeak_extract_contact_content_ids_test.rb +0 -2
- data/test/govspeak_footnote_test.rb +31 -0
- data/test/govspeak_images_bang_test.rb +30 -32
- data/test/govspeak_images_test.rb +36 -38
- data/test/govspeak_link_extractor_test.rb +1 -1
- data/test/govspeak_link_test.rb +0 -2
- data/test/govspeak_structured_headers_test.rb +5 -4
- data/test/govspeak_table_with_headers_test.rb +67 -20
- data/test/govspeak_test.rb +80 -83
- data/test/govspeak_test_helper.rb +1 -1
- data/test/html_sanitizer_test.rb +0 -1
- data/test/presenters/h_card_presenter_test.rb +0 -2
- data/test/test_helper.rb +6 -2
- metadata +48 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26ef4d3bfb3ed9dcf07d44a1428e815928a4fa1ee94f388de829bb999b3cd79c
|
4
|
+
data.tar.gz: c2982f083911dcaf38a0883d48e9ca302a3b514b7bc05b99b827830c02db884d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f75532f9905ae86df812be38a837d60abe1007cad72e8d886c95019f2563734a9e136368b74c1d1499d41bc8c83b2c3a41f415128c93c7025c4f4aacb9765e6f
|
7
|
+
data.tar.gz: e6ef52ca611f2b3e74e77a3330ddaf602385eb90685b3839c8bd28f4bdf06c21652c50cff4a85fc2b157e8e009e11c5ce9c7c439a92d5abdf78821725fbaba2c
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## 6.5.8
|
2
|
+
|
3
|
+
* Customise footnote markup for accessibility (PR#192)
|
4
|
+
|
5
|
+
## 6.5.7
|
6
|
+
|
7
|
+
* Update GOV.UK Publishing components to version to 23.0.0 or greater
|
8
|
+
|
9
|
+
## 6.5.6
|
10
|
+
|
11
|
+
* Update Kramdown version to 2.3.0 or greater
|
12
|
+
|
13
|
+
## 6.5.5
|
14
|
+
|
15
|
+
* Prevent links in table headers being stripped (PR#187)
|
16
|
+
|
17
|
+
## 6.5.4
|
18
|
+
|
19
|
+
* Require Sanitize to be at least 5.2.1 due to https://nvd.nist.gov/vuln/detail/CVE-2020-4054
|
20
|
+
|
1
21
|
## 6.5.3
|
2
22
|
|
3
23
|
* Use button component for buttons (PR#176)
|
data/Rakefile
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
require "rake"
|
2
2
|
require "rake/testtask"
|
3
|
+
require "rubocop/rake_task"
|
3
4
|
require "bundler"
|
4
5
|
|
5
6
|
Bundler::GemHelper.install_tasks
|
6
7
|
|
8
|
+
RuboCop::RakeTask.new
|
9
|
+
|
7
10
|
desc "Run basic tests"
|
8
|
-
Rake::TestTask.new("test")
|
11
|
+
Rake::TestTask.new("test") do |t|
|
9
12
|
t.libs << "test"
|
10
13
|
t.pattern = "test/*_test.rb"
|
11
14
|
t.verbose = true
|
12
15
|
t.warning = true
|
13
|
-
|
16
|
+
end
|
14
17
|
|
15
|
-
task default: [
|
18
|
+
task default: %i[test rubocop]
|
data/lib/govspeak.rb
CHANGED
@@ -57,7 +57,9 @@ module Govspeak
|
|
57
57
|
@links = Array.wrap(options.delete(:links))
|
58
58
|
@contacts = Array.wrap(options.delete(:contacts))
|
59
59
|
@locale = options.fetch(:locale, "en")
|
60
|
-
@options = { input: PARSER_CLASS_NAME,
|
60
|
+
@options = { input: PARSER_CLASS_NAME,
|
61
|
+
sanitize: true,
|
62
|
+
syntax_highlighter: nil }.merge(options)
|
61
63
|
@options[:entity_output] = :symbolic
|
62
64
|
end
|
63
65
|
|
@@ -108,9 +110,9 @@ module Govspeak
|
|
108
110
|
source = Govspeak::BlockquoteExtraQuoteRemover.remove(source)
|
109
111
|
source = remove_forbidden_characters(source)
|
110
112
|
self.class.extensions.each do |_, regexp, block|
|
111
|
-
source.gsub!(regexp)
|
113
|
+
source.gsub!(regexp) do
|
112
114
|
instance_exec(*Regexp.last_match.captures, &block)
|
113
|
-
|
115
|
+
end
|
114
116
|
end
|
115
117
|
source
|
116
118
|
end
|
@@ -127,20 +129,20 @@ module Govspeak
|
|
127
129
|
end
|
128
130
|
|
129
131
|
def self.surrounded_by(open, close = nil)
|
130
|
-
open = Regexp
|
132
|
+
open = Regexp.escape(open)
|
131
133
|
if close
|
132
|
-
close = Regexp
|
133
|
-
%r
|
134
|
+
close = Regexp.escape(close)
|
135
|
+
%r{(?:\r|\n|^)#{open}(.*?)#{close} *(\r|\n|$)?}m
|
134
136
|
else
|
135
|
-
%r
|
137
|
+
%r{(?:\r|\n|^)#{open}(.*?)#{open}? *(\r|\n|$)}m
|
136
138
|
end
|
137
139
|
end
|
138
140
|
|
139
141
|
def self.wrap_with_div(class_name, character, parser = Kramdown::Document)
|
140
|
-
extension(class_name, surrounded_by(character))
|
142
|
+
extension(class_name, surrounded_by(character)) do |body|
|
141
143
|
content = parser ? parser.new("#{body.strip}\n").to_html : body.strip
|
142
|
-
%
|
143
|
-
|
144
|
+
%(\n<div class="#{class_name}">\n#{content}</div>\n)
|
145
|
+
end
|
144
146
|
end
|
145
147
|
|
146
148
|
def insert_strong_inside_p(body, parser = Govspeak::Document)
|
@@ -160,7 +162,7 @@ module Govspeak
|
|
160
162
|
\s* # any whitespace between opening bracket and link
|
161
163
|
{\/button} # match ending bracket
|
162
164
|
(?:\r|\n|$) # non-capturing match to make sure end of line and linebreak
|
163
|
-
}x)
|
165
|
+
}x) do |attributes, text, href|
|
164
166
|
button_classes = "govuk-button"
|
165
167
|
/cross-domain-tracking:(?<cross_domain_tracking>.[^\s*]+)/ =~ attributes
|
166
168
|
data_attribute = ""
|
@@ -173,36 +175,36 @@ module Govspeak
|
|
173
175
|
text = text.strip
|
174
176
|
href = href.strip
|
175
177
|
|
176
|
-
%
|
177
|
-
|
178
|
+
%(\n<a role="button" class="#{button_classes}" href="#{href}" #{data_attribute}>#{text}</a>\n)
|
179
|
+
end
|
178
180
|
|
179
|
-
extension("highlight-answer")
|
180
|
-
%
|
181
|
-
#{Govspeak::Document.new(body.strip).to_html}</div>\n
|
182
|
-
|
181
|
+
extension("highlight-answer") do |body|
|
182
|
+
%(\n\n<div class="highlight-answer">
|
183
|
+
#{Govspeak::Document.new(body.strip).to_html}</div>\n)
|
184
|
+
end
|
183
185
|
|
184
|
-
extension("stat-headline", %r${stat-headline}(.*?){/stat-headline}$m)
|
185
|
-
%
|
186
|
-
#{Govspeak::Document.new(body.strip).to_html}</aside>\n
|
187
|
-
|
186
|
+
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)
|
189
|
+
end
|
188
190
|
|
189
191
|
# FIXME: these surrounded_by arguments look dodgy
|
190
|
-
extension("external", surrounded_by("x[", ")x"))
|
192
|
+
extension("external", surrounded_by("x[", ")x")) do |body|
|
191
193
|
Kramdown::Document.new("[#{body.strip}){:rel='external'}").to_html
|
192
|
-
|
194
|
+
end
|
193
195
|
|
194
|
-
extension("informational", surrounded_by("^"))
|
195
|
-
%
|
196
|
-
#{Govspeak::Document.new(body.strip).to_html}</div>\n
|
197
|
-
|
196
|
+
extension("informational", surrounded_by("^")) do |body|
|
197
|
+
%(\n\n<div role="note" aria-label="Information" class="application-notice info-notice">
|
198
|
+
#{Govspeak::Document.new(body.strip).to_html}</div>\n)
|
199
|
+
end
|
198
200
|
|
199
|
-
extension("important", surrounded_by("@"))
|
200
|
-
%
|
201
|
-
|
201
|
+
extension("important", surrounded_by("@")) do |body|
|
202
|
+
%(\n\n<div role="note" aria-label="Important" class="advisory">#{insert_strong_inside_p(body)}</div>\n)
|
203
|
+
end
|
202
204
|
|
203
|
-
extension("helpful", surrounded_by("%"))
|
204
|
-
%
|
205
|
-
|
205
|
+
extension("helpful", surrounded_by("%")) do |body|
|
206
|
+
%(\n\n<div role="note" aria-label="Warning" class="application-notice help-notice">\n#{Govspeak::Document.new(body.strip).to_html}</div>\n)
|
207
|
+
end
|
206
208
|
|
207
209
|
extension("barchart", /{barchart(.*?)}/) do |captures|
|
208
210
|
stacked = ".mc-stacked" if captures.include? "stacked"
|
@@ -210,13 +212,13 @@ module Govspeak
|
|
210
212
|
negative = ".mc-negative" if captures.include? "negative"
|
211
213
|
|
212
214
|
[
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
215
|
+
"{:",
|
216
|
+
".js-barchart-table",
|
217
|
+
stacked,
|
218
|
+
compact,
|
219
|
+
negative,
|
220
|
+
".mc-auto-outdent",
|
221
|
+
"}",
|
220
222
|
].join(" ")
|
221
223
|
end
|
222
224
|
|
@@ -234,12 +236,12 @@ module Govspeak
|
|
234
236
|
|
235
237
|
attachment = AttachmentPresenter.new(attachment)
|
236
238
|
|
237
|
-
span_id = attachment.id ? %
|
239
|
+
span_id = attachment.id ? %( id="attachment_#{attachment.id}") : ""
|
238
240
|
# new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
|
239
241
|
title = (attachment.title || "").tr("\n", " ")
|
240
242
|
link = attachment.link(title, attachment.url)
|
241
243
|
attributes = attachment.attachment_attributes.empty? ? "" : " (#{attachment.attachment_attributes})"
|
242
|
-
%
|
244
|
+
%(<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>)
|
243
245
|
end
|
244
246
|
|
245
247
|
# DEPRECATED: use 'Image:image-id' instead
|
@@ -261,10 +263,10 @@ module Govspeak
|
|
261
263
|
#
|
262
264
|
# This issue is not considered a bug by kramdown: https://github.com/gettalong/kramdown/issues/191
|
263
265
|
def render_image(image)
|
264
|
-
id_attr = image.id ? %
|
266
|
+
id_attr = image.id ? %( id="attachment_#{image.id}") : ""
|
265
267
|
lines = []
|
266
|
-
lines << %
|
267
|
-
lines << %
|
268
|
+
lines << %(<figure#{id_attr} class="image embedded">)
|
269
|
+
lines << %(<div class="img"><img src="#{encode(image.url)}" alt="#{encode(image.alt_text)}"></div>)
|
268
270
|
lines << image.figcaption_html if image.figcaption?
|
269
271
|
lines << "</figure>"
|
270
272
|
lines.join
|
@@ -279,9 +281,9 @@ module Govspeak
|
|
279
281
|
wrap_with_div("example", "$E", Govspeak::Document)
|
280
282
|
wrap_with_div("call-to-action", "$CTA", Govspeak::Document)
|
281
283
|
|
282
|
-
extension("address", surrounded_by("$A"))
|
283
|
-
%
|
284
|
-
|
284
|
+
extension("address", surrounded_by("$A")) do |body|
|
285
|
+
%(\n<div class="address"><div class="adr org fn"><p>\n#{body.sub("\n", '').gsub("\n", '<br />')}\n</p></div></div>\n)
|
286
|
+
end
|
285
287
|
|
286
288
|
extension("legislative list", /#{NEW_PARAGRAPH_LOOKBEHIND}\$LegislativeList\s*$(.*?)\$EndLegislativeList/m) do |body|
|
287
289
|
Govspeak::KramdownOverrides.with_kramdown_ordered_lists_disabled do
|
@@ -295,9 +297,9 @@ module Govspeak
|
|
295
297
|
|
296
298
|
extension("numbered list", /^[ \t]*((s\d+\.\s.*(?:\n|$))+)/) do |body|
|
297
299
|
body.gsub!(/s(\d+)\.\s(.*)(?:\n|$)/) do
|
298
|
-
"<li>#{Govspeak::Document.new(
|
300
|
+
"<li>#{Govspeak::Document.new(Regexp.last_match(2).strip).to_html}</li>\n"
|
299
301
|
end
|
300
|
-
%
|
302
|
+
%(<ol class="steps">\n#{body}</ol>)
|
301
303
|
end
|
302
304
|
|
303
305
|
def self.devolved_options
|
@@ -362,13 +364,13 @@ module Govspeak
|
|
362
364
|
extension("Attachment", /#{NEW_PARAGRAPH_LOOKBEHIND}\[Attachment:\s*(.*?)\s*\]/) do |attachment_id|
|
363
365
|
next "" if attachments.none? { |a| a[:id] == attachment_id }
|
364
366
|
|
365
|
-
%
|
367
|
+
%(<govspeak-embed-attachment id="#{attachment_id}"></govspeak-embed-attachment>)
|
366
368
|
end
|
367
369
|
|
368
370
|
extension("AttachmentLink", /\[AttachmentLink:\s*(.*?)\s*\]/) do |attachment_id|
|
369
371
|
next "" if attachments.none? { |a| a[:id] == attachment_id }
|
370
372
|
|
371
|
-
%
|
373
|
+
%(<govspeak-embed-attachment-link id="#{attachment_id}"></govspeak-embed-attachment-link>)
|
372
374
|
end
|
373
375
|
|
374
376
|
private
|
@@ -54,12 +54,12 @@ class Govspeak::HtmlSanitizer
|
|
54
54
|
elements: Sanitize::Config::RELAXED[:elements] + %w[govspeak-embed-attachment govspeak-embed-attachment-link svg path],
|
55
55
|
attributes: {
|
56
56
|
:all => Sanitize::Config::RELAXED[:attributes][:all] + %w[role aria-label],
|
57
|
-
"a"
|
57
|
+
"a" => Sanitize::Config::RELAXED[:attributes]["a"] + [:data],
|
58
58
|
"svg" => Sanitize::Config::RELAXED[:attributes][:all] + %w[xmlns width height viewbox focusable],
|
59
59
|
"path" => Sanitize::Config::RELAXED[:attributes][:all] + %w[fill d],
|
60
60
|
"div" => [:data],
|
61
|
-
"th"
|
62
|
-
"td"
|
61
|
+
"th" => Sanitize::Config::RELAXED[:attributes]["th"] + %w[style],
|
62
|
+
"td" => Sanitize::Config::RELAXED[:attributes]["td"] + %w[style],
|
63
63
|
"govspeak-embed-attachment" => %w[content-id],
|
64
64
|
},
|
65
65
|
)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Govspeak
|
2
2
|
module KramdownOverrides
|
3
|
-
#
|
3
|
+
# This depends on two internal parts of Kramdown.
|
4
4
|
# 1. Parser registry (kramdown/parser/kramdown.rb#define_parser)
|
5
5
|
# 2. Kramdown list regexes (kramdown/parser/kramdown/list.rb)
|
6
|
-
#
|
6
|
+
# Updating the Kramdown gem therefore also means updating this file to to
|
7
7
|
# match Kramdown's internals.
|
8
8
|
|
9
9
|
def self.with_kramdown_ordered_lists_disabled
|
@@ -14,9 +14,9 @@ module Govspeak
|
|
14
14
|
attr_reader :document, :website_root
|
15
15
|
|
16
16
|
def extract_links
|
17
|
-
document_anchors
|
18
|
-
map { |link| extract_href_from_link(link) }
|
19
|
-
reject(&:blank?)
|
17
|
+
document_anchors
|
18
|
+
.map { |link| extract_href_from_link(link) }
|
19
|
+
.reject(&:blank?)
|
20
20
|
end
|
21
21
|
|
22
22
|
def extract_href_from_link(link)
|
@@ -92,11 +92,13 @@ module Govspeak
|
|
92
92
|
end
|
93
93
|
|
94
94
|
document.css(":not(thead) tr td:first-child").map do |el|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
next unless el.content.match?(/^#($|\s.*$)/)
|
96
|
+
|
97
|
+
# Replace '# ' and '#', but not '#Word'.
|
98
|
+
# This runs on the first child of the element to preserve any links
|
99
|
+
el.children.first.content = el.children.first.content.gsub(/^#($|\s)/, "")
|
100
|
+
el.name = "th" if el.content.present? # This also prevents a `th` with nothing inside it; a `td` is preferable.
|
101
|
+
el[:scope] = "row" if el.content.present? # `scope` shouldn't be used if there's nothing in the table heading.
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
@@ -118,6 +120,16 @@ module Govspeak
|
|
118
120
|
end
|
119
121
|
end
|
120
122
|
|
123
|
+
extension("use custom footnotes") do |document|
|
124
|
+
document.css("a.footnote").map do |el|
|
125
|
+
footnote_number = el[:href].gsub(/\D/, "")
|
126
|
+
el.content = "[footnote #{footnote_number}]"
|
127
|
+
end
|
128
|
+
document.css("[role='doc-backlink']").map do |el|
|
129
|
+
el.content = "[go to where this is referenced]"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
121
133
|
attr_reader :input, :govspeak_document
|
122
134
|
|
123
135
|
def initialize(html, govspeak_document)
|
@@ -55,46 +55,46 @@ module Govspeak
|
|
55
55
|
|
56
56
|
def humanized_content_type(file_extension)
|
57
57
|
file_extension_vs_humanized_content_type = {
|
58
|
-
"chm"
|
59
|
-
"csv"
|
58
|
+
"chm" => file_abbr_tag("CHM", "Microsoft Compiled HTML Help"),
|
59
|
+
"csv" => file_abbr_tag("CSV", "Comma-separated Values"),
|
60
60
|
"diff" => file_abbr_tag("DIFF", "Plain text differences"),
|
61
|
-
"doc"
|
61
|
+
"doc" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
62
62
|
"docx" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
63
|
-
"dot"
|
64
|
-
"dxf"
|
65
|
-
"eps"
|
66
|
-
"gif"
|
67
|
-
"gml"
|
63
|
+
"dot" => file_abbr_tag("DOT", "MS Word Document Template"),
|
64
|
+
"dxf" => file_abbr_tag("DXF", "AutoCAD Drawing Exchange Format"),
|
65
|
+
"eps" => file_abbr_tag("EPS", "Encapsulated PostScript"),
|
66
|
+
"gif" => file_abbr_tag("GIF", "Graphics Interchange Format"),
|
67
|
+
"gml" => file_abbr_tag("GML", "Geography Markup Language"),
|
68
68
|
"html" => file_abbr_tag("HTML", "Hypertext Markup Language"),
|
69
69
|
"ics" => file_abbr_tag("ICS", "iCalendar file"),
|
70
|
-
"jpg"
|
71
|
-
"odp"
|
72
|
-
"ods"
|
73
|
-
"odt"
|
74
|
-
"pdf"
|
75
|
-
"png"
|
76
|
-
"ppt"
|
70
|
+
"jpg" => "JPEG",
|
71
|
+
"odp" => file_abbr_tag("ODP", "OpenDocument Presentation"),
|
72
|
+
"ods" => file_abbr_tag("ODS", "OpenDocument Spreadsheet"),
|
73
|
+
"odt" => file_abbr_tag("ODT", "OpenDocument Text document"),
|
74
|
+
"pdf" => file_abbr_tag("PDF", "Portable Document Format"),
|
75
|
+
"png" => file_abbr_tag("PNG", "Portable Network Graphic"),
|
76
|
+
"ppt" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
77
77
|
"pptx" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
78
|
-
"ps"
|
79
|
-
"rdf"
|
80
|
-
"rtf"
|
81
|
-
"sch"
|
82
|
-
"txt"
|
78
|
+
"ps" => file_abbr_tag("PS", "PostScript"),
|
79
|
+
"rdf" => file_abbr_tag("RDF", "Resource Description Framework"),
|
80
|
+
"rtf" => file_abbr_tag("RTF", "Rich Text Format"),
|
81
|
+
"sch" => file_abbr_tag("SCH", "XML based Schematic"),
|
82
|
+
"txt" => "Plain text",
|
83
83
|
"wsdl" => file_abbr_tag("WSDL", "Web Services Description Language"),
|
84
|
-
"xls"
|
84
|
+
"xls" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
85
85
|
"xlsm" => file_abbr_tag("XLSM", "MS Excel Macro-Enabled Workbook"),
|
86
86
|
"xlsx" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
87
|
-
"xlt"
|
88
|
-
"xsd"
|
87
|
+
"xlt" => file_abbr_tag("XLT", "MS Excel Spreadsheet Template"),
|
88
|
+
"xsd" => file_abbr_tag("XSD", "XML Schema"),
|
89
89
|
"xslt" => file_abbr_tag("XSLT", "Extensible Stylesheet Language Transformation"),
|
90
|
-
"zip"
|
90
|
+
"zip" => file_abbr_tag("ZIP", "Zip archive"),
|
91
91
|
}
|
92
92
|
file_extension_vs_humanized_content_type.fetch(file_extension.to_s.downcase, "")
|
93
93
|
end
|
94
94
|
|
95
95
|
def link(body, url, options = {})
|
96
|
-
options_str = options.map { |k, v| %
|
97
|
-
%
|
96
|
+
options_str = options.map { |k, v| %(#{encode(k)}="#{encode(v)}") }.join(" ")
|
97
|
+
%(<a href="#{encode(url)}" #{options_str}>#{body}</a>)
|
98
98
|
end
|
99
99
|
|
100
100
|
private
|
@@ -33,8 +33,8 @@ module Govspeak
|
|
33
33
|
def figcaption_html
|
34
34
|
lines = []
|
35
35
|
lines << "<figcaption>"
|
36
|
-
lines << %
|
37
|
-
lines << %
|
36
|
+
lines << %(<p>#{caption}</p>) if caption.present?
|
37
|
+
lines << %(<p>#{I18n.t('govspeak.image.figure.credit', credit: credit)}</p>) if credit.present?
|
38
38
|
lines << "</figcaption>"
|
39
39
|
lines.join
|
40
40
|
end
|
@@ -48,9 +48,9 @@ module Govspeak
|
|
48
48
|
private :doc, :stack, :structured_headers
|
49
49
|
|
50
50
|
def headers_list
|
51
|
-
@headers_list ||= doc.headers.map
|
51
|
+
@headers_list ||= doc.headers.map do |h|
|
52
52
|
StructuredHeader.new(h.text, h.level, h.id, [])
|
53
|
-
|
53
|
+
end
|
54
54
|
end
|
55
55
|
|
56
56
|
def add_top_level(header)
|
data/lib/govspeak/version.rb
CHANGED
@@ -9,7 +9,7 @@ module Kramdown
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
define(:document_domains, Object, %w
|
12
|
+
define(:document_domains, Object, %w[www.gov.uk], <<~DESCRIPTION) do |val|
|
13
13
|
Defines the domains which are considered local to the document
|
14
14
|
|
15
15
|
Default: www.gov.uk
|
@@ -21,10 +21,10 @@ module Kramdown
|
|
21
21
|
|
22
22
|
module Parser
|
23
23
|
class Govuk < Kramdown::Parser::Kramdown
|
24
|
-
CUSTOM_INLINE_ELEMENTS = %w
|
24
|
+
CUSTOM_INLINE_ELEMENTS = %w[govspeak-embed-attachment-link].freeze
|
25
25
|
|
26
26
|
def initialize(source, options)
|
27
|
-
@document_domains = options[:document_domains] || %w
|
27
|
+
@document_domains = options[:document_domains] || %w[www.gov.uk]
|
28
28
|
super
|
29
29
|
end
|
30
30
|
|
@@ -35,11 +35,10 @@ module Kramdown
|
|
35
35
|
unless host.nil? || @document_domains.compact.include?(host)
|
36
36
|
element.attr["rel"] = "external"
|
37
37
|
end
|
38
|
-
# rubocop:disable Lint/SuppressedException
|
39
38
|
rescue Addressable::URI::InvalidURIError
|
40
39
|
# it's safe to ignore these very *specific* exceptions
|
41
40
|
end
|
42
|
-
|
41
|
+
|
43
42
|
end
|
44
43
|
super
|
45
44
|
end
|