govspeak 5.0.0 → 5.0.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +273 -9
- data/lib/govspeak.rb +9 -9
- data/lib/govspeak/presenters/attachment_presenter.rb +288 -0
- data/lib/govspeak/presenters/contact_presenter.rb +24 -0
- data/lib/govspeak/presenters/h_card_presenter.rb +71 -0
- data/lib/govspeak/version.rb +1 -1
- data/test/govspeak_link_test.rb +17 -6
- metadata +5 -5
- data/lib/presenters/attachment_presenter.rb +0 -286
- data/lib/presenters/contact_presenter.rb +0 -22
- data/lib/presenters/h_card_presenter.rb +0 -69
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 177a638111a0d8d422e3201f0e3e265218fb1cb9
|
|
4
|
+
data.tar.gz: 5be0baf8e84b10bfd28f0f5ed6e1c5e292fe4c1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77ca5d6c13299db9221804e96b01fb15412d0c38d3017219304992d225dab4382dec796015fd2533e62e7ad734d6f0199b216b175e4f45d099cc913b8ed24a6a
|
|
7
|
+
data.tar.gz: b52ed84b08d05f85c44a2a3bb3fe2d86835f2cf9934e9ead9b7c143b9be9fcbea03b84d8af70ca2245426a9ea1676b54a35a2714d7a3e679ad890d1ee87f46d9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 5.0.1
|
|
2
|
+
* Move presenters into the Govspeak namespace [#93](https://github.com/alphagov/govspeak/pull/93)
|
|
3
|
+
* Embedded links now will automatically be marked with `rel="external"` [#96](https://github.com/alphagov/govspeak/pull/96)
|
|
4
|
+
|
|
1
5
|
## 5.0.0
|
|
2
6
|
* Update Kramdown version to 1.12.0
|
|
3
7
|
* Add pry-byebug to development dependencies
|
data/README.md
CHANGED
|
@@ -43,7 +43,7 @@ In addition to the [standard Markdown syntax](http://daringfireball.net/projects
|
|
|
43
43
|
creates a callout with an info (i) icon.
|
|
44
44
|
|
|
45
45
|
<div role="note" aria-label="Information" class="application-notice info-notice">
|
|
46
|
-
|
|
46
|
+
<p>This is an information callout</p>
|
|
47
47
|
</div>
|
|
48
48
|
|
|
49
49
|
### Warning callouts
|
|
@@ -53,7 +53,7 @@ creates a callout with an info (i) icon.
|
|
|
53
53
|
creates a callout with a warning or alert (!) icon
|
|
54
54
|
|
|
55
55
|
<div role="note" aria-label="Help" class="application-notice help-notice">
|
|
56
|
-
|
|
56
|
+
<p>This is a warning callout</p>
|
|
57
57
|
</div>
|
|
58
58
|
|
|
59
59
|
### Example callout
|
|
@@ -158,6 +158,74 @@ creates a file download box
|
|
|
158
158
|
<p><a href="http://example.com/" title="Example form" rel="external">An example form download link.</a></p>
|
|
159
159
|
</div>
|
|
160
160
|
|
|
161
|
+
## Place
|
|
162
|
+
|
|
163
|
+
$P
|
|
164
|
+
This is a place
|
|
165
|
+
$P
|
|
166
|
+
|
|
167
|
+
creates a place box
|
|
168
|
+
|
|
169
|
+
<div class="place">
|
|
170
|
+
<p>This is a place</p>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
## Information
|
|
174
|
+
|
|
175
|
+
$I
|
|
176
|
+
This is information
|
|
177
|
+
$I
|
|
178
|
+
|
|
179
|
+
creates an information box
|
|
180
|
+
|
|
181
|
+
<div class="information">
|
|
182
|
+
<p>This is information</p>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
185
|
+
## Additional Information
|
|
186
|
+
|
|
187
|
+
$AI
|
|
188
|
+
This is additional information
|
|
189
|
+
$AI
|
|
190
|
+
|
|
191
|
+
creates an additional information box
|
|
192
|
+
|
|
193
|
+
<div class="additional-information">
|
|
194
|
+
<p>This is additional information</p>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
## Call to Action
|
|
198
|
+
|
|
199
|
+
$CTA
|
|
200
|
+
This is a call to action
|
|
201
|
+
$CTA
|
|
202
|
+
|
|
203
|
+
creates an additional information box
|
|
204
|
+
|
|
205
|
+
<div class="call-to-action">
|
|
206
|
+
<p>This is a call to action</p>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
## Summary
|
|
210
|
+
|
|
211
|
+
$!
|
|
212
|
+
This is a summary
|
|
213
|
+
$!
|
|
214
|
+
|
|
215
|
+
creates a summary box
|
|
216
|
+
|
|
217
|
+
<div class="summary">
|
|
218
|
+
<p>This is a summary</p>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
## External Link
|
|
222
|
+
|
|
223
|
+
x[External Report](https://example.com/report)x
|
|
224
|
+
|
|
225
|
+
creates a link specified as external
|
|
226
|
+
|
|
227
|
+
<a href="https://example.com/report" rel="external">External Report</a>
|
|
228
|
+
|
|
161
229
|
## Steps
|
|
162
230
|
|
|
163
231
|
Steps can be created similar to an ordered list:
|
|
@@ -183,17 +251,26 @@ For lists where you want to specify the numbering and have multiple indent level
|
|
|
183
251
|
$EndLegislativeList
|
|
184
252
|
(to indent, add 2 spaces)
|
|
185
253
|
|
|
186
|
-
##
|
|
187
|
-
|
|
188
|
-
Abbreviations can be defined at the end of the document, and any occurrences elswhere in the document will wrapped in an `<abbr>` tag. They are parsed in the order in which they are defined, so `PCSOs` should be defined before `PCSO`, for example.
|
|
254
|
+
## Priority Lists
|
|
189
255
|
|
|
190
|
-
|
|
256
|
+
For lists where you want to specify a number of items to be highlighted as priority.
|
|
191
257
|
|
|
192
|
-
|
|
258
|
+
$PriorityList:3
|
|
259
|
+
- Item 1
|
|
260
|
+
- Item 2
|
|
261
|
+
- Item 3
|
|
262
|
+
- Item 4
|
|
263
|
+
- Item 5
|
|
193
264
|
|
|
194
|
-
|
|
265
|
+
creates a list with priority items flagged with a class
|
|
195
266
|
|
|
196
|
-
<
|
|
267
|
+
<ul>
|
|
268
|
+
<li class="primary-item">Item 1</li>
|
|
269
|
+
<li class="primary-item">Item 2</li>
|
|
270
|
+
<li class="primary-item">Item 3</li>
|
|
271
|
+
<li>Item 4</li>
|
|
272
|
+
<li>Item 5</li>
|
|
273
|
+
</ul>
|
|
197
274
|
|
|
198
275
|
## Devolved content
|
|
199
276
|
|
|
@@ -203,3 +280,190 @@ becomes
|
|
|
203
280
|
:wales:content goes here:wales:
|
|
204
281
|
:northern-ireland:content goes here:northern-ireland:
|
|
205
282
|
:england-wales:content goes here:england-wales:
|
|
283
|
+
|
|
284
|
+
will create a box for the specified locality
|
|
285
|
+
|
|
286
|
+
<div class="devolved-content england">
|
|
287
|
+
<p class="devolved-header">This section applies to England</p>
|
|
288
|
+
<div class="devolved-body">
|
|
289
|
+
<p>content goes here</p>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
## Barcharts
|
|
294
|
+
|
|
295
|
+
For when you want a table to be progressively enhanced by Javascript to be
|
|
296
|
+
rendered as a bar chart.
|
|
297
|
+
|
|
298
|
+
|col|
|
|
299
|
+
|---|
|
|
300
|
+
|val|
|
|
301
|
+
{barchart}
|
|
302
|
+
|
|
303
|
+
will be rendered as
|
|
304
|
+
<table class="js-barchart-table mc-auto-outdent">
|
|
305
|
+
<thead>
|
|
306
|
+
<tr>
|
|
307
|
+
<th>col</th>
|
|
308
|
+
</tr>
|
|
309
|
+
</thead>
|
|
310
|
+
<tbody>
|
|
311
|
+
<tr>
|
|
312
|
+
<td>val</td>
|
|
313
|
+
</tr>
|
|
314
|
+
</tbody>
|
|
315
|
+
</table>
|
|
316
|
+
|
|
317
|
+
## Embedded Content
|
|
318
|
+
|
|
319
|
+
Embedded content allows authors to reference a supporting item of a document by
|
|
320
|
+
referencing an id. The details of this content is passed to the publishing
|
|
321
|
+
application to govspeak at the time of rendering.
|
|
322
|
+
|
|
323
|
+
### Attachments
|
|
324
|
+
|
|
325
|
+
To create an attachment callout
|
|
326
|
+
|
|
327
|
+
[embed:attachment:2b4d92f3-f8cd-4284-aaaa-25b3a640d26c]
|
|
328
|
+
|
|
329
|
+
with options provided
|
|
330
|
+
|
|
331
|
+
{
|
|
332
|
+
attachments: [
|
|
333
|
+
{
|
|
334
|
+
id: 123,
|
|
335
|
+
content_id: "2b4d92f3-f8cd-4284-aaaa-25b3a640d26c",
|
|
336
|
+
title: "Attachment Title",
|
|
337
|
+
url: "http://example.com/test.pdf",
|
|
338
|
+
order_url: "http://example.com/order",
|
|
339
|
+
price: 12.3,
|
|
340
|
+
isbn: "isbn-123",
|
|
341
|
+
attachment?: true,
|
|
342
|
+
}
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
will output an attachment box
|
|
347
|
+
|
|
348
|
+
<section class="attachment embedded">
|
|
349
|
+
<div class="attachment-thumb">
|
|
350
|
+
<a href="http://example.com/test.pdf" aria-hidden="true" class="embedded"><img src="/images/pub-cover.png" alt="Pub cover"></a>
|
|
351
|
+
</div>
|
|
352
|
+
<div class="attachment-details">
|
|
353
|
+
<h2 class="title">
|
|
354
|
+
<a href="http://example.com/test.pdf" aria-describedby="attachment-123-accessibility-help">Attachment Title</a>
|
|
355
|
+
</h2>
|
|
356
|
+
<p class="metadata">
|
|
357
|
+
<span class="references">Ref: ISBN <span class="isbn">isbn-123</span></span>
|
|
358
|
+
</p>
|
|
359
|
+
<p>
|
|
360
|
+
<a href="http://example.com/order" class="order_url" title="Order a copy of the publication">Order a copy</a>(<span class="price">£12.30</span>)
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
363
|
+
</section>
|
|
364
|
+
|
|
365
|
+
### Inline Attachment
|
|
366
|
+
|
|
367
|
+
Attachments can be linked to inline as well
|
|
368
|
+
|
|
369
|
+
Details referenced in [embed:attachments:inline:34f6dda0-21b1-4e78-8120-3ff4dcea522d]
|
|
370
|
+
|
|
371
|
+
with options provided
|
|
372
|
+
|
|
373
|
+
{
|
|
374
|
+
attachments: [
|
|
375
|
+
{
|
|
376
|
+
content_id: "34f6dda0-21b1-4e78-8120-3ff4dcea522d",
|
|
377
|
+
title: "My Thorough Study",
|
|
378
|
+
url: "http://example.com/my-thorough-study.pdf",
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
will output an attachment within a block of text
|
|
384
|
+
|
|
385
|
+
<p>Details referenced in <span class="attachment-inline"><a href="http://example.com/my-thorough-study.pdf">My Thorough Study</a></span>
|
|
386
|
+
|
|
387
|
+
### Image Attachments
|
|
388
|
+
|
|
389
|
+
Attachments can be used to embed an image within the document
|
|
390
|
+
|
|
391
|
+
[embed:attachments:image:45ee0eea-bc53-4f14-81eb-9e75d33c4d5e]
|
|
392
|
+
|
|
393
|
+
with options provided
|
|
394
|
+
|
|
395
|
+
{
|
|
396
|
+
attachments: [
|
|
397
|
+
{
|
|
398
|
+
content_id: "45ee0eea-bc53-4f14-81eb-9e75d33c4d5e",
|
|
399
|
+
title: "A lovely landscape",
|
|
400
|
+
url: "http://example.com/lovely-landscape.jpg",
|
|
401
|
+
}
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
will output a image section
|
|
406
|
+
|
|
407
|
+
<figure class="image embedded"><div class="img"><img src="http://example.com/lovely-landscape.jpg" alt="A Lovely Landscape"></div></figure>
|
|
408
|
+
|
|
409
|
+
### Link
|
|
410
|
+
|
|
411
|
+
Links to different documents can be embedded so they change when the documents
|
|
412
|
+
they reference change.
|
|
413
|
+
|
|
414
|
+
A link to [embed:link:c636b433-1e5c-46d4-96b0-b5a168fac26c]
|
|
415
|
+
|
|
416
|
+
with options provided
|
|
417
|
+
|
|
418
|
+
{
|
|
419
|
+
links: [
|
|
420
|
+
{
|
|
421
|
+
url: "http://example.com",
|
|
422
|
+
title: "An excellent website",
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
will output
|
|
428
|
+
|
|
429
|
+
<p>A link to <a href="http://example.com">An excellent website</a></p>
|
|
430
|
+
|
|
431
|
+
### Contact
|
|
432
|
+
|
|
433
|
+
[Contact:df62690f-34a0-4840-a7fa-4ef5acc18666]
|
|
434
|
+
|
|
435
|
+
with options provided
|
|
436
|
+
|
|
437
|
+
{
|
|
438
|
+
contacts: [
|
|
439
|
+
{
|
|
440
|
+
id: 123,
|
|
441
|
+
content_id: "df62690f-34a0-4840-a7fa-4ef5acc18666",
|
|
442
|
+
title: "Government Digital Service",
|
|
443
|
+
email: "people@digital.cabinet-office.gov.uk",
|
|
444
|
+
contact_numbers: [
|
|
445
|
+
{ label: "helpdesk", number: "+4412345 67890"}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
]
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
will output
|
|
452
|
+
|
|
453
|
+
<div id="contact_123" class="contact">
|
|
454
|
+
<div class="content">
|
|
455
|
+
<h3>Government Digital Service</h3>
|
|
456
|
+
<div class="vcard contact-inner">
|
|
457
|
+
<div class="email-url-number">
|
|
458
|
+
<p class="email">
|
|
459
|
+
<span class="type">Email</span>
|
|
460
|
+
<a href="mailto:people@digital.cabinet-office.gov.uk" class="email">people@digital.cabinet-office.gov.uk</a>
|
|
461
|
+
</p>
|
|
462
|
+
<p class="tel">
|
|
463
|
+
<span class="type">helpdesk</span>
|
|
464
|
+
+4412345 67890
|
|
465
|
+
</p>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
</div>
|
data/lib/govspeak.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
require 'kramdown'
|
|
2
1
|
require 'active_support/core_ext/hash'
|
|
3
2
|
require 'active_support/core_ext/array'
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'htmlentities'
|
|
5
|
+
require 'kramdown'
|
|
6
|
+
require 'kramdown/parser/kramdown_with_automatic_external_links'
|
|
4
7
|
require 'govspeak/header_extractor'
|
|
5
8
|
require 'govspeak/structured_header_extractor'
|
|
6
9
|
require 'govspeak/html_validator'
|
|
@@ -8,12 +11,9 @@ require 'govspeak/html_sanitizer'
|
|
|
8
11
|
require 'govspeak/kramdown_overrides'
|
|
9
12
|
require 'govspeak/blockquote_extra_quote_remover'
|
|
10
13
|
require 'govspeak/post_processor'
|
|
11
|
-
require '
|
|
12
|
-
require '
|
|
13
|
-
require 'presenters/
|
|
14
|
-
require 'presenters/contact_presenter'
|
|
15
|
-
require 'presenters/h_card_presenter'
|
|
16
|
-
require 'erb'
|
|
14
|
+
require 'govspeak/presenters/attachment_presenter'
|
|
15
|
+
require 'govspeak/presenters/contact_presenter'
|
|
16
|
+
require 'govspeak/presenters/h_card_presenter'
|
|
17
17
|
|
|
18
18
|
module Govspeak
|
|
19
19
|
|
|
@@ -32,7 +32,7 @@ module Govspeak
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def initialize(source, options = {})
|
|
35
|
-
options.deep_symbolize_keys
|
|
35
|
+
options = options.dup.deep_symbolize_keys
|
|
36
36
|
@source = source ? source.dup : ""
|
|
37
37
|
@images = options.delete(:images) || []
|
|
38
38
|
@attachments = Array.wrap(options.delete(:attachments))
|
|
@@ -303,7 +303,7 @@ module Govspeak
|
|
|
303
303
|
link = links.detect { |l| l[:content_id].match(content_id) }
|
|
304
304
|
next "" unless link
|
|
305
305
|
if link[:url]
|
|
306
|
-
|
|
306
|
+
"[#{link[:title]}](#{link[:url]})"
|
|
307
307
|
else
|
|
308
308
|
link[:title]
|
|
309
309
|
end
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
require "action_view"
|
|
2
|
+
require "money"
|
|
3
|
+
require "htmlentities"
|
|
4
|
+
|
|
5
|
+
module Govspeak
|
|
6
|
+
class AttachmentPresenter
|
|
7
|
+
attr_reader :attachment
|
|
8
|
+
include ActionView::Helpers::TagHelper
|
|
9
|
+
include ActionView::Helpers::NumberHelper
|
|
10
|
+
include ActionView::Helpers::AssetTagHelper
|
|
11
|
+
include ActionView::Helpers::TextHelper
|
|
12
|
+
|
|
13
|
+
def initialize(attachment)
|
|
14
|
+
@attachment = attachment
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def id
|
|
18
|
+
attachment[:id]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def order_url
|
|
22
|
+
attachment[:order_url]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def opendocument?
|
|
26
|
+
attachment[:opendocument?]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def url
|
|
30
|
+
attachment[:url]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def external?
|
|
34
|
+
attachment[:external?]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def price
|
|
38
|
+
return unless attachment[:price]
|
|
39
|
+
Money.from_amount(attachment[:price], 'GBP').format
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def accessible?
|
|
43
|
+
attachment[:accessible?]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def thumbnail_link
|
|
47
|
+
return if hide_thumbnail?
|
|
48
|
+
return if previewable?
|
|
49
|
+
link(attachment_thumbnail, url, "aria-hidden" => "true", "class" => attachment_class)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def help_block_toggle_id
|
|
53
|
+
"attachment-#{id}-accessibility-request"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def section_class
|
|
57
|
+
attachment[:external?] ? "hosted-externally" : "embedded"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def mail_to(email_address, name, options = {})
|
|
61
|
+
query_string = options.slice(:subject, :body).map { |k, v| "#{urlencode(k)}=#{urlencode(v)}" }.join("&")
|
|
62
|
+
"<a href='mailto:#{encode(email_address)}?#{encode(query_string)}'>#{name}</a>"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def alternative_format_order_link
|
|
66
|
+
attachment_info = []
|
|
67
|
+
attachment_info << " Title: #{title}"
|
|
68
|
+
attachment_info << " Original format: #{file_extension}" if file_extension.present?
|
|
69
|
+
attachment_info << " ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
|
70
|
+
attachment_info << " Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
|
71
|
+
attachment_info << " Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
|
72
|
+
if attachment[:hoc_paper_number].present?
|
|
73
|
+
attachment_info << " House of Commons paper number: #{attachment[:hoc_paper_number]}"
|
|
74
|
+
attachment_info << " Parliamentary session: #{attachment[:parliamentary_session]}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
options = {
|
|
78
|
+
subject: "Request for '#{title}' in an alternative format",
|
|
79
|
+
body: body_for_mail(attachment_info)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
mail_to(alternative_format_contact_email, alternative_format_contact_email, options)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def body_for_mail(attachment_info)
|
|
86
|
+
<<-END
|
|
87
|
+
Details of document required:
|
|
88
|
+
|
|
89
|
+
#{attachment_info.join("\n")}
|
|
90
|
+
|
|
91
|
+
Please tell us:
|
|
92
|
+
|
|
93
|
+
1. What makes this format unsuitable for you?
|
|
94
|
+
2. What format you would prefer?
|
|
95
|
+
END
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def alternative_format_contact_email
|
|
99
|
+
"govuk-feedback@digital.cabinet-office.gov.uk"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# FIXME: usage of image_tag will cause these to render at /images/ which seems
|
|
103
|
+
# very host dependent. I assume this will need links to static urls.
|
|
104
|
+
def attachment_thumbnail
|
|
105
|
+
if file_extension == "pdf" && attachment[:thumbnail_url]
|
|
106
|
+
image_tag(attachment[:thumbnail_url])
|
|
107
|
+
elsif file_extension == "html"
|
|
108
|
+
image_tag('pub-cover-html.png')
|
|
109
|
+
elsif %w{doc docx odt}.include?(file_extension)
|
|
110
|
+
image_tag('pub-cover-doc.png')
|
|
111
|
+
elsif %w{xls xlsx ods csv}.include?(file_extension)
|
|
112
|
+
image_tag('pub-cover-spreadsheet.png')
|
|
113
|
+
else
|
|
114
|
+
image_tag('pub-cover.png')
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def reference
|
|
119
|
+
ref = []
|
|
120
|
+
if attachment[:isbn].present?
|
|
121
|
+
ref << "ISBN " + content_tag(:span, attachment[:isbn], class: "isbn")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
if attachment[:unique_reference].present?
|
|
125
|
+
ref << content_tag(:span, attachment[:unique_reference], class: "unique_reference")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if attachment[:command_paper_number].present?
|
|
129
|
+
ref << content_tag(:span, attachment[:command_paper_number], class: "command_paper_number")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
if attachment[:hoc_paper_number].present?
|
|
133
|
+
ref << content_tag(:span, "HC #{attachment[:hoc_paper_number]}", class: 'house_of_commons_paper_number') + ' ' +
|
|
134
|
+
content_tag(:span, attachment[:parliamentary_session], class: 'parliamentary_session')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
ref.join(', ').html_safe
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# FIXME this has english in it so will cause problems if the locale is not en
|
|
141
|
+
def references_for_title
|
|
142
|
+
references = []
|
|
143
|
+
references << "ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
|
144
|
+
references << "Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
|
145
|
+
references << "Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
|
146
|
+
references << "HC: #{attachment[:hoc_paper_number]} #{attachment[:parliamentary_session]}" if attachment[:hoc_paper_number].present?
|
|
147
|
+
prefix = references.size == 1 ? "and its reference" : "and its references"
|
|
148
|
+
references.any? ? ", #{prefix} (" + references.join(", ") + ")" : ""
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def references?
|
|
152
|
+
!attachment[:isbn].to_s.empty? || !attachment[:unique_reference].to_s.empty? || !attachment[:command_paper_number].to_s.empty? || !attachment[:hoc_paper_number].to_s.empty?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def attachment_class
|
|
156
|
+
attachment[:external?] ? "hosted-externally" : "embedded"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def unnumbered_paper?
|
|
160
|
+
attachment[:unnumbered_command_paper?] || attachment[:unnumbered_hoc_paper?]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def unnumbered_command_paper?
|
|
164
|
+
attachment[:unnumbered_command_paper?]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def download_link
|
|
168
|
+
options = {}
|
|
169
|
+
options[:title] = number_to_human_size(attachment[:file_size]) if attachment[:file_size].present?
|
|
170
|
+
link("<strong>Download #{file_extension.upcase}</strong>", attachment[:url], options)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def attachment_attributes
|
|
174
|
+
attributes = []
|
|
175
|
+
if file_extension == "html"
|
|
176
|
+
attributes << content_tag(:span, 'HTML', class: 'type')
|
|
177
|
+
elsif attachment[:external?]
|
|
178
|
+
attributes << content_tag(:span, url, class: 'url')
|
|
179
|
+
else
|
|
180
|
+
attributes << content_tag(:span, humanized_content_type(file_extension), class: 'type') if file_extension
|
|
181
|
+
attributes << content_tag(:span, number_to_human_size(attachment[:file_size]), class: 'file-size') if attachment[:file_size]
|
|
182
|
+
attributes << content_tag(:span, pluralize(attachment[:number_of_pages], "page"), class: 'page-length') if attachment[:number_of_pages]
|
|
183
|
+
end
|
|
184
|
+
attributes.join(', ').html_safe
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def preview_url
|
|
188
|
+
url + '/preview'
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE = "MS Word Document".freeze
|
|
192
|
+
MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE = "MS Excel Spreadsheet".freeze
|
|
193
|
+
MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE = "MS Powerpoint Presentation".freeze
|
|
194
|
+
|
|
195
|
+
def file_abbr_tag(abbr, title)
|
|
196
|
+
content_tag(:abbr, abbr, title: title)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def humanized_content_type(file_extension)
|
|
200
|
+
file_extension_vs_humanized_content_type = {
|
|
201
|
+
"chm" => file_abbr_tag('CHM', 'Microsoft Compiled HTML Help'),
|
|
202
|
+
"csv" => file_abbr_tag('CSV', 'Comma-separated Values'),
|
|
203
|
+
"diff" => file_abbr_tag('DIFF', 'Plain text differences'),
|
|
204
|
+
"doc" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
|
205
|
+
"docx" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
|
206
|
+
"dot" => file_abbr_tag('DOT', 'MS Word Document Template'),
|
|
207
|
+
"dxf" => file_abbr_tag('DXF', 'AutoCAD Drawing Exchange Format'),
|
|
208
|
+
"eps" => file_abbr_tag('EPS', 'Encapsulated PostScript'),
|
|
209
|
+
"gif" => file_abbr_tag('GIF', 'Graphics Interchange Format'),
|
|
210
|
+
"gml" => file_abbr_tag('GML', 'Geography Markup Language'),
|
|
211
|
+
"html" => file_abbr_tag('HTML', 'Hypertext Markup Language'),
|
|
212
|
+
"ics" => file_abbr_tag('ICS', 'iCalendar file'),
|
|
213
|
+
"jpg" => "JPEG",
|
|
214
|
+
"odp" => file_abbr_tag('ODP', 'OpenDocument Presentation'),
|
|
215
|
+
"ods" => file_abbr_tag('ODS', 'OpenDocument Spreadsheet'),
|
|
216
|
+
"odt" => file_abbr_tag('ODT', 'OpenDocument Text document'),
|
|
217
|
+
"pdf" => file_abbr_tag('PDF', 'Portable Document Format'),
|
|
218
|
+
"png" => file_abbr_tag('PNG', 'Portable Network Graphic'),
|
|
219
|
+
"ppt" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
|
220
|
+
"pptx" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
|
221
|
+
"ps" => file_abbr_tag('PS', 'PostScript'),
|
|
222
|
+
"rdf" => file_abbr_tag('RDF', 'Resource Description Framework'),
|
|
223
|
+
"rtf" => file_abbr_tag('RTF', 'Rich Text Format'),
|
|
224
|
+
"sch" => file_abbr_tag('SCH', 'XML based Schematic'),
|
|
225
|
+
"txt" => "Plain text",
|
|
226
|
+
"wsdl" => file_abbr_tag('WSDL', 'Web Services Description Language'),
|
|
227
|
+
"xls" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
|
228
|
+
"xlsm" => file_abbr_tag('XLSM', 'MS Excel Macro-Enabled Workbook'),
|
|
229
|
+
"xlsx" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
|
230
|
+
"xlt" => file_abbr_tag('XLT', 'MS Excel Spreadsheet Template'),
|
|
231
|
+
"xsd" => file_abbr_tag('XSD', 'XML Schema'),
|
|
232
|
+
"xslt" => file_abbr_tag('XSLT', 'Extensible Stylesheet Language Transformation'),
|
|
233
|
+
"zip" => file_abbr_tag('ZIP', 'Zip archive'),
|
|
234
|
+
}
|
|
235
|
+
file_extension_vs_humanized_content_type.fetch(file_extension.to_s.downcase, '')
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def previewable?
|
|
239
|
+
file_extension == "csv"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def title
|
|
243
|
+
attachment[:title]
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def file_extension
|
|
247
|
+
# Note: this is a separate parameter rather than being calculated from the
|
|
248
|
+
# filename because at the time of writing not all apps were using the effects
|
|
249
|
+
# of this field.
|
|
250
|
+
attachment[:file_extension]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def hide_thumbnail?
|
|
254
|
+
defined?(hide_thumbnail) && hide_thumbnail
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def attachment_details
|
|
258
|
+
return if previewable?
|
|
259
|
+
link(title, url, title_link_options)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def title_link_options
|
|
263
|
+
title_link_options = {}
|
|
264
|
+
title_link_options["rel"] = "external" if attachment[:external?]
|
|
265
|
+
title_link_options["aria-describedby"] = help_block_id unless attachment[:accessible?]
|
|
266
|
+
title_link_options
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def help_block_id
|
|
270
|
+
"attachment-#{id}-accessibility-help"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def link(body, url, options = {})
|
|
274
|
+
options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
|
|
275
|
+
%{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
private
|
|
279
|
+
|
|
280
|
+
def encode(text)
|
|
281
|
+
HTMLEntities.new.encode(text)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def urlencode(text)
|
|
285
|
+
ERB::Util.url_encode(text)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'active_support/core_ext/array'
|
|
2
|
+
require 'ostruct'
|
|
3
|
+
|
|
4
|
+
module Govspeak
|
|
5
|
+
class ContactPresenter
|
|
6
|
+
attr_reader :contact
|
|
7
|
+
delegate :id, :content_id, :title, :recipient, :street_address, :postal_code,
|
|
8
|
+
:locality, :region, :country_code, :country_name, :email, :contact_form_url,
|
|
9
|
+
:comments, :worldwide_organisation_path, to: :contact
|
|
10
|
+
|
|
11
|
+
def initialize(contact)
|
|
12
|
+
@contact = OpenStruct.new(contact)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def contact_numbers
|
|
16
|
+
Array.wrap(contact[:contact_numbers])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def has_postal_address?
|
|
20
|
+
recipient.present? || street_address.present? || locality.present? ||
|
|
21
|
+
region.present? || postal_code.present?
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Govspeak
|
|
2
|
+
class HCardPresenter
|
|
3
|
+
def self.from_contact(contact)
|
|
4
|
+
new(contact_properties(contact), contact.country_code)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.contact_properties(contact)
|
|
8
|
+
{ 'fn' => contact.recipient,
|
|
9
|
+
'street-address' => contact.street_address,
|
|
10
|
+
'postal-code' => contact.postal_code,
|
|
11
|
+
'locality' => contact.locality,
|
|
12
|
+
'region' => contact.region,
|
|
13
|
+
'country-name' => country_name(contact) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.country_name(contact)
|
|
17
|
+
contact.country_name unless contact.country_code == 'GB'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.property_keys
|
|
21
|
+
['fn', 'street-address', 'postal-code', 'locality', 'region', 'country-name']
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.address_formats
|
|
25
|
+
@address_formats ||= YAML.load_file('config/address_formats.yml')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
attr_reader :properties, :country_code
|
|
29
|
+
|
|
30
|
+
def initialize(properties, country_code)
|
|
31
|
+
@properties = properties
|
|
32
|
+
@country_code = country_code
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def render
|
|
36
|
+
"<p class=\"adr\">\n#{interpolate_address_template}\n</p>\n".html_safe
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def interpolate_address_property(property_name)
|
|
40
|
+
value = properties[property_name]
|
|
41
|
+
|
|
42
|
+
if value.present?
|
|
43
|
+
"<span class=\"#{property_name}\">#{ERB::Util.html_escape(value)}</span>"
|
|
44
|
+
else
|
|
45
|
+
""
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def interpolate_address_template
|
|
52
|
+
address = address_template
|
|
53
|
+
|
|
54
|
+
self.class.property_keys.each do |key|
|
|
55
|
+
address.gsub!(/\{\{#{key}\}\}/, interpolate_address_property(key))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
address.gsub(/^\n/, '') # get rid of blank lines
|
|
59
|
+
.strip # get rid of any trailing whitespace
|
|
60
|
+
.gsub(/\n/, "<br />\n") # add break tags where appropriate
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def address_template
|
|
64
|
+
(self.class.address_formats[country_code.to_s.downcase] || default_format_string).dup
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def default_format_string
|
|
68
|
+
self.class.address_formats['gb']
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/govspeak/version.rb
CHANGED
data/test/govspeak_link_test.rb
CHANGED
|
@@ -6,27 +6,38 @@ class GovspeakLinkTest < Minitest::Test
|
|
|
6
6
|
test "embedded link with link provided" do
|
|
7
7
|
link = {
|
|
8
8
|
content_id: "5572fee5-f38f-4641-8ffa-64fed9230ad4",
|
|
9
|
-
url: "https://www.
|
|
10
|
-
title: "Example
|
|
9
|
+
url: "https://www.gov.uk/example",
|
|
10
|
+
title: "Example page",
|
|
11
11
|
}
|
|
12
12
|
govspeak = "[embed:link:5572fee5-f38f-4641-8ffa-64fed9230ad4]"
|
|
13
13
|
rendered = Govspeak::Document.new(govspeak, links: link).to_html
|
|
14
|
-
expected = %r{<a href="https://www.
|
|
14
|
+
expected = %r{<a href="https://www.gov.uk/example">Example page</a>}
|
|
15
15
|
assert_match(expected, rendered)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
test "embedded link with markdown title" do
|
|
19
19
|
link = {
|
|
20
20
|
content_id: "5572fee5-f38f-4641-8ffa-64fed9230ad4",
|
|
21
|
-
url: "https://www.
|
|
22
|
-
title: "**Example
|
|
21
|
+
url: "https://www.gov.uk/example",
|
|
22
|
+
title: "**Example page**",
|
|
23
23
|
}
|
|
24
24
|
govspeak = "[embed:link:5572fee5-f38f-4641-8ffa-64fed9230ad4]"
|
|
25
25
|
rendered = Govspeak::Document.new(govspeak, links: link).to_html
|
|
26
|
-
expected = %r{<a href="https://www.
|
|
26
|
+
expected = %r{<a href="https://www.gov.uk/example"><strong>Example page</strong></a>}
|
|
27
27
|
assert_match(expected, rendered)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
test "embedded link with external url" do
|
|
31
|
+
link = {
|
|
32
|
+
content_id: "5572fee5-f38f-4641-8ffa-64fed9230ad4",
|
|
33
|
+
url: "https://www.example.com/",
|
|
34
|
+
title: "Example website",
|
|
35
|
+
}
|
|
36
|
+
govspeak = "[embed:link:5572fee5-f38f-4641-8ffa-64fed9230ad4]"
|
|
37
|
+
rendered = Govspeak::Document.new(govspeak, links: link).to_html
|
|
38
|
+
expected = %r{<a rel="external" href="https://www.example.com/">Example website</a>}
|
|
39
|
+
assert_match(expected, rendered)
|
|
40
|
+
end
|
|
30
41
|
test "embedded link with url not provided" do
|
|
31
42
|
link = {
|
|
32
43
|
content_id: "e510f1c1-4862-4333-889c-8d3acd443fbf",
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: govspeak
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.0.
|
|
4
|
+
version: 5.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ben Griffiths
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2016-
|
|
12
|
+
date: 2016-10-04 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: kramdown
|
|
@@ -251,12 +251,12 @@ files:
|
|
|
251
251
|
- lib/govspeak/html_validator.rb
|
|
252
252
|
- lib/govspeak/kramdown_overrides.rb
|
|
253
253
|
- lib/govspeak/post_processor.rb
|
|
254
|
+
- lib/govspeak/presenters/attachment_presenter.rb
|
|
255
|
+
- lib/govspeak/presenters/contact_presenter.rb
|
|
256
|
+
- lib/govspeak/presenters/h_card_presenter.rb
|
|
254
257
|
- lib/govspeak/structured_header_extractor.rb
|
|
255
258
|
- lib/govspeak/version.rb
|
|
256
259
|
- lib/kramdown/parser/kramdown_with_automatic_external_links.rb
|
|
257
|
-
- lib/presenters/attachment_presenter.rb
|
|
258
|
-
- lib/presenters/contact_presenter.rb
|
|
259
|
-
- lib/presenters/h_card_presenter.rb
|
|
260
260
|
- lib/templates/attachment.html.erb
|
|
261
261
|
- lib/templates/contact.html.erb
|
|
262
262
|
- lib/templates/inline_attachment.html.erb
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
require "action_view"
|
|
2
|
-
require "money"
|
|
3
|
-
require "htmlentities"
|
|
4
|
-
|
|
5
|
-
class AttachmentPresenter
|
|
6
|
-
attr_reader :attachment
|
|
7
|
-
include ActionView::Helpers::TagHelper
|
|
8
|
-
include ActionView::Helpers::NumberHelper
|
|
9
|
-
include ActionView::Helpers::AssetTagHelper
|
|
10
|
-
include ActionView::Helpers::TextHelper
|
|
11
|
-
|
|
12
|
-
def initialize(attachment)
|
|
13
|
-
@attachment = attachment
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def id
|
|
17
|
-
attachment[:id]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def order_url
|
|
21
|
-
attachment[:order_url]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def opendocument?
|
|
25
|
-
attachment[:opendocument?]
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def url
|
|
29
|
-
attachment[:url]
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def external?
|
|
33
|
-
attachment[:external?]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def price
|
|
37
|
-
return unless attachment[:price]
|
|
38
|
-
Money.from_amount(attachment[:price], 'GBP').format
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def accessible?
|
|
42
|
-
attachment[:accessible?]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def thumbnail_link
|
|
46
|
-
return if hide_thumbnail?
|
|
47
|
-
return if previewable?
|
|
48
|
-
link(attachment_thumbnail, url, "aria-hidden" => "true", "class" => attachment_class)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def help_block_toggle_id
|
|
52
|
-
"attachment-#{id}-accessibility-request"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def section_class
|
|
56
|
-
attachment[:external?] ? "hosted-externally" : "embedded"
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def mail_to(email_address, name, options = {})
|
|
60
|
-
query_string = options.slice(:subject, :body).map { |k, v| "#{urlencode(k)}=#{urlencode(v)}" }.join("&")
|
|
61
|
-
"<a href='mailto:#{encode(email_address)}?#{encode(query_string)}'>#{name}</a>"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def alternative_format_order_link
|
|
65
|
-
attachment_info = []
|
|
66
|
-
attachment_info << " Title: #{title}"
|
|
67
|
-
attachment_info << " Original format: #{file_extension}" if file_extension.present?
|
|
68
|
-
attachment_info << " ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
|
69
|
-
attachment_info << " Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
|
70
|
-
attachment_info << " Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
|
71
|
-
if attachment[:hoc_paper_number].present?
|
|
72
|
-
attachment_info << " House of Commons paper number: #{attachment[:hoc_paper_number]}"
|
|
73
|
-
attachment_info << " Parliamentary session: #{attachment[:parliamentary_session]}"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
options = {
|
|
77
|
-
subject: "Request for '#{title}' in an alternative format",
|
|
78
|
-
body: body_for_mail(attachment_info)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
mail_to(alternative_format_contact_email, alternative_format_contact_email, options)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def body_for_mail(attachment_info)
|
|
85
|
-
<<-END
|
|
86
|
-
Details of document required:
|
|
87
|
-
|
|
88
|
-
#{attachment_info.join("\n")}
|
|
89
|
-
|
|
90
|
-
Please tell us:
|
|
91
|
-
|
|
92
|
-
1. What makes this format unsuitable for you?
|
|
93
|
-
2. What format you would prefer?
|
|
94
|
-
END
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def alternative_format_contact_email
|
|
98
|
-
"govuk-feedback@digital.cabinet-office.gov.uk"
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# FIXME: usage of image_tag will cause these to render at /images/ which seems
|
|
102
|
-
# very host dependent. I assume this will need links to static urls.
|
|
103
|
-
def attachment_thumbnail
|
|
104
|
-
if file_extension == "pdf" && attachment[:thumbnail_url]
|
|
105
|
-
image_tag(attachment[:thumbnail_url])
|
|
106
|
-
elsif file_extension == "html"
|
|
107
|
-
image_tag('pub-cover-html.png')
|
|
108
|
-
elsif %w{doc docx odt}.include?(file_extension)
|
|
109
|
-
image_tag('pub-cover-doc.png')
|
|
110
|
-
elsif %w{xls xlsx ods csv}.include?(file_extension)
|
|
111
|
-
image_tag('pub-cover-spreadsheet.png')
|
|
112
|
-
else
|
|
113
|
-
image_tag('pub-cover.png')
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def reference
|
|
118
|
-
ref = []
|
|
119
|
-
if attachment[:isbn].present?
|
|
120
|
-
ref << "ISBN " + content_tag(:span, attachment[:isbn], class: "isbn")
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
if attachment[:unique_reference].present?
|
|
124
|
-
ref << content_tag(:span, attachment[:unique_reference], class: "unique_reference")
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
if attachment[:command_paper_number].present?
|
|
128
|
-
ref << content_tag(:span, attachment[:command_paper_number], class: "command_paper_number")
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
if attachment[:hoc_paper_number].present?
|
|
132
|
-
ref << content_tag(:span, "HC #{attachment[:hoc_paper_number]}", class: 'house_of_commons_paper_number') + ' ' +
|
|
133
|
-
content_tag(:span, attachment[:parliamentary_session], class: 'parliamentary_session')
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
ref.join(', ').html_safe
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# FIXME this has english in it so will cause problems if the locale is not en
|
|
140
|
-
def references_for_title
|
|
141
|
-
references = []
|
|
142
|
-
references << "ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
|
|
143
|
-
references << "Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
|
|
144
|
-
references << "Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
|
|
145
|
-
references << "HC: #{attachment[:hoc_paper_number]} #{attachment[:parliamentary_session]}" if attachment[:hoc_paper_number].present?
|
|
146
|
-
prefix = references.size == 1 ? "and its reference" : "and its references"
|
|
147
|
-
references.any? ? ", #{prefix} (" + references.join(", ") + ")" : ""
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def references?
|
|
151
|
-
!attachment[:isbn].to_s.empty? || !attachment[:unique_reference].to_s.empty? || !attachment[:command_paper_number].to_s.empty? || !attachment[:hoc_paper_number].to_s.empty?
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def attachment_class
|
|
155
|
-
attachment[:external?] ? "hosted-externally" : "embedded"
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def unnumbered_paper?
|
|
159
|
-
attachment[:unnumbered_command_paper?] || attachment[:unnumbered_hoc_paper?]
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def unnumbered_command_paper?
|
|
163
|
-
attachment[:unnumbered_command_paper?]
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def download_link
|
|
167
|
-
options = {}
|
|
168
|
-
options[:title] = number_to_human_size(attachment[:file_size]) if attachment[:file_size].present?
|
|
169
|
-
link("<strong>Download #{file_extension.upcase}</strong>", attachment[:url], options)
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def attachment_attributes
|
|
173
|
-
attributes = []
|
|
174
|
-
if file_extension == "html"
|
|
175
|
-
attributes << content_tag(:span, 'HTML', class: 'type')
|
|
176
|
-
elsif attachment[:external?]
|
|
177
|
-
attributes << content_tag(:span, url, class: 'url')
|
|
178
|
-
else
|
|
179
|
-
attributes << content_tag(:span, humanized_content_type(file_extension), class: 'type') if file_extension
|
|
180
|
-
attributes << content_tag(:span, number_to_human_size(attachment[:file_size]), class: 'file-size') if attachment[:file_size]
|
|
181
|
-
attributes << content_tag(:span, pluralize(attachment[:number_of_pages], "page"), class: 'page-length') if attachment[:number_of_pages]
|
|
182
|
-
end
|
|
183
|
-
attributes.join(', ').html_safe
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def preview_url
|
|
187
|
-
url + '/preview'
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE = "MS Word Document"
|
|
191
|
-
MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE = "MS Excel Spreadsheet"
|
|
192
|
-
MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE = "MS Powerpoint Presentation"
|
|
193
|
-
|
|
194
|
-
def file_abbr_tag(abbr, title)
|
|
195
|
-
content_tag(:abbr, abbr, title: title)
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def humanized_content_type(file_extension)
|
|
199
|
-
file_extension_vs_humanized_content_type = {
|
|
200
|
-
"chm" => file_abbr_tag('CHM', 'Microsoft Compiled HTML Help'),
|
|
201
|
-
"csv" => file_abbr_tag('CSV', 'Comma-separated Values'),
|
|
202
|
-
"diff" => file_abbr_tag('DIFF', 'Plain text differences'),
|
|
203
|
-
"doc" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
|
204
|
-
"docx" => MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE,
|
|
205
|
-
"dot" => file_abbr_tag('DOT', 'MS Word Document Template'),
|
|
206
|
-
"dxf" => file_abbr_tag('DXF', 'AutoCAD Drawing Exchange Format'),
|
|
207
|
-
"eps" => file_abbr_tag('EPS', 'Encapsulated PostScript'),
|
|
208
|
-
"gif" => file_abbr_tag('GIF', 'Graphics Interchange Format'),
|
|
209
|
-
"gml" => file_abbr_tag('GML', 'Geography Markup Language'),
|
|
210
|
-
"html" => file_abbr_tag('HTML', 'Hypertext Markup Language'),
|
|
211
|
-
"ics" => file_abbr_tag('ICS', 'iCalendar file'),
|
|
212
|
-
"jpg" => "JPEG",
|
|
213
|
-
"odp" => file_abbr_tag('ODP', 'OpenDocument Presentation'),
|
|
214
|
-
"ods" => file_abbr_tag('ODS', 'OpenDocument Spreadsheet'),
|
|
215
|
-
"odt" => file_abbr_tag('ODT', 'OpenDocument Text document'),
|
|
216
|
-
"pdf" => file_abbr_tag('PDF', 'Portable Document Format'),
|
|
217
|
-
"png" => file_abbr_tag('PNG', 'Portable Network Graphic'),
|
|
218
|
-
"ppt" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
|
219
|
-
"pptx" => MS_POWERPOINT_PRESENTATION_HUMANIZED_CONTENT_TYPE,
|
|
220
|
-
"ps" => file_abbr_tag('PS', 'PostScript'),
|
|
221
|
-
"rdf" => file_abbr_tag('RDF', 'Resource Description Framework'),
|
|
222
|
-
"rtf" => file_abbr_tag('RTF', 'Rich Text Format'),
|
|
223
|
-
"sch" => file_abbr_tag('SCH', 'XML based Schematic'),
|
|
224
|
-
"txt" => "Plain text",
|
|
225
|
-
"wsdl" => file_abbr_tag('WSDL', 'Web Services Description Language'),
|
|
226
|
-
"xls" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
|
227
|
-
"xlsm" => file_abbr_tag('XLSM', 'MS Excel Macro-Enabled Workbook'),
|
|
228
|
-
"xlsx" => MS_EXCEL_SPREADSHEET_HUMANIZED_CONTENT_TYPE,
|
|
229
|
-
"xlt" => file_abbr_tag('XLT', 'MS Excel Spreadsheet Template'),
|
|
230
|
-
"xsd" => file_abbr_tag('XSD', 'XML Schema'),
|
|
231
|
-
"xslt" => file_abbr_tag('XSLT', 'Extensible Stylesheet Language Transformation'),
|
|
232
|
-
"zip" => file_abbr_tag('ZIP', 'Zip archive'),
|
|
233
|
-
}
|
|
234
|
-
file_extension_vs_humanized_content_type.fetch(file_extension.to_s.downcase, '')
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def previewable?
|
|
238
|
-
file_extension == "csv"
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def title
|
|
242
|
-
attachment[:title]
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def file_extension
|
|
246
|
-
# Note: this is a separate parameter rather than being calculated from the
|
|
247
|
-
# filename because at the time of writing not all apps were using the effects
|
|
248
|
-
# of this field.
|
|
249
|
-
attachment[:file_extension]
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def hide_thumbnail?
|
|
253
|
-
defined?(hide_thumbnail) && hide_thumbnail
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def attachment_details
|
|
257
|
-
return if previewable?
|
|
258
|
-
link(title, url, title_link_options)
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def title_link_options
|
|
262
|
-
title_link_options = {}
|
|
263
|
-
title_link_options["rel"] = "external" if attachment[:external?]
|
|
264
|
-
title_link_options["aria-describedby"] = help_block_id unless attachment[:accessible?]
|
|
265
|
-
title_link_options
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
def help_block_id
|
|
269
|
-
"attachment-#{id}-accessibility-help"
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
def link(body, url, options = {})
|
|
273
|
-
options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
|
|
274
|
-
%{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
private
|
|
278
|
-
|
|
279
|
-
def encode(text)
|
|
280
|
-
HTMLEntities.new.encode(text)
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def urlencode(text)
|
|
284
|
-
ERB::Util.url_encode(text)
|
|
285
|
-
end
|
|
286
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require 'active_support/core_ext/array'
|
|
2
|
-
require 'ostruct'
|
|
3
|
-
|
|
4
|
-
class ContactPresenter
|
|
5
|
-
attr_reader :contact
|
|
6
|
-
delegate :id, :content_id, :title, :recipient, :street_address, :postal_code,
|
|
7
|
-
:locality, :region, :country_code, :country_name, :email, :contact_form_url,
|
|
8
|
-
:comments, :worldwide_organisation_path, to: :contact
|
|
9
|
-
|
|
10
|
-
def initialize(contact)
|
|
11
|
-
@contact = OpenStruct.new(contact)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def contact_numbers
|
|
15
|
-
Array.wrap(contact[:contact_numbers])
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def has_postal_address?
|
|
19
|
-
recipient.present? || street_address.present? || locality.present? ||
|
|
20
|
-
region.present? || postal_code.present?
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
class HCardPresenter
|
|
2
|
-
def self.from_contact(contact)
|
|
3
|
-
new(contact_properties(contact), contact.country_code)
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
def self.contact_properties(contact)
|
|
7
|
-
{ 'fn' => contact.recipient,
|
|
8
|
-
'street-address' => contact.street_address,
|
|
9
|
-
'postal-code' => contact.postal_code,
|
|
10
|
-
'locality' => contact.locality,
|
|
11
|
-
'region' => contact.region,
|
|
12
|
-
'country-name' => country_name(contact) }
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.country_name(contact)
|
|
16
|
-
contact.country_name unless contact.country_code == 'GB'
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.property_keys
|
|
20
|
-
['fn', 'street-address', 'postal-code', 'locality', 'region', 'country-name']
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def self.address_formats
|
|
24
|
-
@address_formats ||= YAML.load_file('config/address_formats.yml')
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
attr_reader :properties, :country_code
|
|
28
|
-
|
|
29
|
-
def initialize(properties, country_code)
|
|
30
|
-
@properties = properties
|
|
31
|
-
@country_code = country_code
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def render
|
|
35
|
-
"<p class=\"adr\">\n#{interpolate_address_template}\n</p>\n".html_safe
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def interpolate_address_property(property_name)
|
|
39
|
-
value = properties[property_name]
|
|
40
|
-
|
|
41
|
-
if value.present?
|
|
42
|
-
"<span class=\"#{property_name}\">#{ERB::Util.html_escape(value)}</span>"
|
|
43
|
-
else
|
|
44
|
-
""
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def interpolate_address_template
|
|
51
|
-
address = address_template
|
|
52
|
-
|
|
53
|
-
self.class.property_keys.each do |key|
|
|
54
|
-
address.gsub!(/\{\{#{key}\}\}/, interpolate_address_property(key))
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
address.gsub(/^\n/, '') # get rid of blank lines
|
|
58
|
-
.strip # get rid of any trailing whitespace
|
|
59
|
-
.gsub(/\n/, "<br />\n") # add break tags where appropriate
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def address_template
|
|
63
|
-
(self.class.address_formats[country_code.to_s.downcase] || default_format_string).dup
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def default_format_string
|
|
67
|
-
self.class.address_formats['gb']
|
|
68
|
-
end
|
|
69
|
-
end
|