Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use hashes as options for govspeak extensions #89

Merged
merged 13 commits into from
Sep 28, 2016
34 changes: 20 additions & 14 deletions lib/govspeak.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'kramdown'
require 'active_support/core_ext/hash'
require 'active_support/core_ext/array'
require 'govspeak/header_extractor'
require 'govspeak/structured_header_extractor'
require 'govspeak/html_validator'
Expand All @@ -10,6 +11,7 @@
require 'kramdown/parser/kramdown_with_automatic_external_links'
require 'htmlentities'
require 'presenters/attachment_presenter'
require 'presenters/contact_presenter'
require 'presenters/h_card_presenter'
require 'erb'

Expand All @@ -33,9 +35,9 @@ def initialize(source, options = {})
options.deep_symbolize_keys!
@source = source ? source.dup : ""
@images = options.delete(:images) || []
@attachments = Array(options.delete(:attachments))
@links = Array(options.delete(:links))
@contacts = Array(options.delete(:contacts))
@attachments = Array.wrap(options.delete(:attachments))
@links = Array.wrap(options.delete(:links))
@contacts = Array.wrap(options.delete(:contacts))
@locale = options.fetch(:locale, "en")
@options = {input: PARSER_CLASS_NAME}.merge(options)
@options[:entity_output] = :symbolic
Expand Down Expand Up @@ -188,19 +190,22 @@ def insert_strong_inside_p(body, parser=Govspeak::Document)
end

extension('attachment', /\[embed:attachments:([0-9a-f-]+)\]/) do |content_id, body|
attachment = attachments.detect { |a| a.content_id.match(content_id) }
attachment = attachments.detect { |a| a[:content_id].match(content_id) }
next "" unless attachment
attachment = AttachmentPresenter.new(attachment)
content = File.read('lib/govspeak/extension/attachment.html.erb')
content = File.read(__dir__ + '/templates/attachment.html.erb')
ERB.new(content).result(binding)
end

extension('attachment inline', /\[embed:attachments:inline:([0-9a-f-]+)\]/) do |content_id, body|
attachment = attachments.detect { |a| a.content_id.match(content_id) }
attachment = attachments.detect { |a| a[:content_id].match(content_id) }
next "" unless attachment
attachment = AttachmentPresenter.new(attachment)
content = File.read('lib/govspeak/extension/inline_attachment.html.erb')
ERB.new(content).result(binding)
span_id = attachment.id ? %{ id="attachment_#{attachment.id}"} : ""
# new lines inside our title cause problems with govspeak rendering as this is expected to be on one line.
link = attachment.link(attachment.title.gsub("\n", " "), attachment.url)
attributes = attachment.attachment_attributes.empty? ? "" : " (#{attachment.attachment_attributes})"
%{<span#{span_id} class="attachment-inline">#{link}#{attributes}</span>}
end

def render_image(url, alt_text, caption = nil)
Expand Down Expand Up @@ -275,12 +280,12 @@ def self.devolved_options
end

extension('embed link', /\[embed:link:([0-9a-f-]+)\]/) do |content_id|
link = links.detect { |l| l.content_id.match(content_id) }
link = links.detect { |l| l[:content_id].match(content_id) }
next "" unless link
if link.url
%Q{<a href="#{encode(link.url)}">#{encode(link.title)}</a>}
if link[:url]
%Q{<a href="#{encode(link[:url])}">#{link[:title]}</a>}
else
encode(link.title)
link[:title]
end
end

Expand All @@ -290,9 +295,10 @@ def render_hcard_address(contact)
private :render_hcard_address

extension('Contact', /\[Contact:([0-9a-f-]+)\]/) do |content_id|
contact = contacts.detect { |c| c.content_id.match(content_id) }
contact = contacts.detect { |c| c[:content_id].match(content_id) }
next "" unless contact
@renderer ||= ERB.new(File.read('lib/templates/contact.html.erb'))
contact = ContactPresenter.new(contact)
@renderer ||= ERB.new(File.read(__dir__ + '/templates/contact.html.erb'))
@renderer.result(binding)
end
end
Expand Down
4 changes: 0 additions & 4 deletions lib/govspeak/extension/inline_attachment.html.erb

This file was deleted.

159 changes: 102 additions & 57 deletions lib/presenters/attachment_presenter.rb
Original file line number Diff line number Diff line change
@@ -1,77 +1,80 @@
require "action_view"
require "money"
require "htmlentities"

class AttachmentPresenter
attr_reader :attachment
include ActionView::Helpers::TagHelper
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::TextHelper

def initialize(attachment)
@attachment = attachment
end

def id
attachment.id
attachment[:id]
end

def order_url
attachment.order_url
attachment[:order_url]
end

def opendocument?
attachment.opendocument?
attachment[:opendocument?]
end

def url
attachment.url
attachment[:url]
end

def external?
attachment.external?
attachment[:external?]
end

def price
return unless attachment.price
Money.from_amount(attachment.price, 'GBP').format
return unless attachment[:price]
Money.from_amount(attachment[:price], 'GBP').format
end

def accessible?
attachment.accessible?
attachment[:accessible?]
end

def thumbnail_link
return if hide_thumbnail?
return if previewable?
link(attachment_thumbnail, url, "aria-hidden=true class=#{attachment_class}")
link(attachment_thumbnail, url, "aria-hidden" => "true", "class" => attachment_class)
end

def help_block_toggle_id
"attachment-#{attachment.id}-accessibility-request"
"attachment-#{id}-accessibility-request"
end

def section_class
attachment.external? ? "hosted-externally" : "embedded"
attachment[:external?] ? "hosted-externally" : "embedded"
end

def mail_to(email_address, name, options = {})
"<a href='mailto:#{email_address}?Subject=#{options[:subject]}&body=#{options[:body]}'>#{name}</a>"
query_string = options.slice(:subject, :body).map { |k, v| "#{urlencode(k)}=#{urlencode(v)}" }.join("&")
"<a href='mailto:#{encode(email_address)}?#{encode(query_string)}'>#{name}</a>"
end

def alternative_format_order_link
attachment_info = []
attachment_info << " Title: #{attachment.title}"
attachment_info << " Original format: #{attachment.file_extension}"
attachment_info << " ISBN: #{attachment.isbn}" if attachment.isbn.present?
attachment_info << " Unique reference: #{attachment.unique_reference}" if attachment.unique_reference.present?
attachment_info << " Command paper number: #{attachment.command_paper_number}" if attachment.command_paper_number.present?
if attachment.hoc_paper_number.present?
attachment_info << " House of Commons paper number: #{attachment.hoc_paper_number}"
attachment_info << " Parliamentary session: #{attachment.parliamentary_session}"
attachment_info << " Title: #{title}"
attachment_info << " Original format: #{file_extension}" if file_extension.present?
attachment_info << " ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
attachment_info << " Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
attachment_info << " Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
if attachment[:hoc_paper_number].present?
attachment_info << " House of Commons paper number: #{attachment[:hoc_paper_number]}"
attachment_info << " Parliamentary session: #{attachment[:parliamentary_session]}"
end

options = {
subject: "Request for '#{attachment.title}' in an alternative format",
subject: "Request for '#{title}' in an alternative format",
body: body_for_mail(attachment_info)
}

Expand All @@ -80,7 +83,7 @@ def alternative_format_order_link

def body_for_mail(attachment_info)
<<-END
Details of document required:
Details of document required:

#{attachment_info.join("\n")}

Expand All @@ -95,66 +98,93 @@ def alternative_format_contact_email
"govuk-feedback@digital.cabinet-office.gov.uk"
end

# FIXME: usage of image_tag will cause these to render at /images/ which seems
# very host dependent. I assume this will need links to static urls.
def attachment_thumbnail
if attachment.pdf?
image_tag(attachment.file.thumbnail.url)
elsif attachment.html?
if file_extension == "pdf" && attachment[:thumbnail_url]
image_tag(attachment[:thumbnail_url])
elsif file_extension == "html"
image_tag('pub-cover-html.png')
elsif %w{doc docx odt}.include? attachment.file_extension
elsif %w{doc docx odt}.include?(file_extension)
image_tag('pub-cover-doc.png')
elsif %w{xls xlsx ods csv}.include? attachment.file_extension
elsif %w{xls xlsx ods csv}.include?(file_extension)
image_tag('pub-cover-spreadsheet.png')
else
image_tag('pub-cover.png')
end
end

def references
def reference
ref = []
if attachment[:isbn].present?
ref << "ISBN " + content_tag(:span, attachment[:isbn], class: "isbn")
end

if attachment[:unique_reference].present?
ref << content_tag(:span, attachment[:unique_reference], class: "unique_reference")
end

if attachment[:command_paper_number].present?
ref << content_tag(:span, attachment[:command_paper_number], class: "command_paper_number")
end

if attachment[:hoc_paper_number].present?
ref << content_tag(:span, "HC #{attachment[:hoc_paper_number]}", class: 'house_of_commons_paper_number') + ' ' +
content_tag(:span, attachment[:parliamentary_session], class: 'parliamentary_session')
end

ref.join(', ').html_safe
end

# FIXME this has english in it so will cause problems if the locale is not en
def references_for_title
references = []
references << "ISBN: #{attachment.isbn}" if attachment.isbn.present?
references << "Unique reference: #{attachment.unique_reference}" if attachment.unique_reference.present?
references << "Command paper number: #{attachment.command_paper_number}" if attachment.command_paper_number.present?
references << "HC: #{attachment.hoc_paper_number} #{attachment.parliamentary_session}" if attachment.hoc_paper_number.present?
references << "ISBN: #{attachment[:isbn]}" if attachment[:isbn].present?
references << "Unique reference: #{attachment[:unique_reference]}" if attachment[:unique_reference].present?
references << "Command paper number: #{attachment[:command_paper_number]}" if attachment[:command_paper_number].present?
references << "HC: #{attachment[:hoc_paper_number]} #{attachment[:parliamentary_session]}" if attachment[:hoc_paper_number].present?
prefix = references.size == 1 ? "and its reference" : "and its references"
references.any? ? ", #{prefix} (" + references.join(", ") + ")" : ""
end

def references?
!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?
!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?
end

def attachment_class
attachment.external? ? "hosted-externally" : "embedded"
attachment[:external?] ? "hosted-externally" : "embedded"
end

def unnumbered_paper?
attachment.unnumbered_command_paper? || attachment.unnumbered_hoc_paper?
attachment[:unnumbered_command_paper?] || attachment[:unnumbered_hoc_paper?]
end

def unnumbered_command_paper?
attachment.unnumbered_command_paper?
attachment[:unnumbered_command_paper?]
end

def download_link
link(attachment.preview_url, "<strong>Download #{attachment.file_extension.upcase}</strong>", number_to_human_size(attachment.file_size))
options = {}
options[:title] = number_to_human_size(attachment[:file_size]) if attachment[:file_size].present?
link("<strong>Download #{file_extension.upcase}</strong>", attachment[:url], options)
end

def attachment_attributes
attributes = []
if attachment.html?
if file_extension == "html"
attributes << content_tag(:span, 'HTML', class: 'type')
elsif attachment.external?
elsif attachment[:external?]
attributes << content_tag(:span, url, class: 'url')
else
attributes << content_tag(:span, humanized_content_type(attachment.file_extension), class: 'type')
attributes << content_tag(:span, number_to_human_size(attachment.file_size), class: 'file-size')
attributes << content_tag(:span, pluralize(attachment.number_of_pages, "page") , class: 'page-length') if attachment.number_of_pages.present?
attributes << content_tag(:span, humanized_content_type(file_extension), class: 'type') if file_extension
attributes << content_tag(:span, number_to_human_size(attachment[:file_size]), class: 'file-size') if attachment[:file_size]
attributes << content_tag(:span, pluralize(attachment[:number_of_pages], "page"), class: 'page-length') if attachment[:number_of_pages]
end
attributes.join(', ').html_safe
end

def preview_url
url << '/preview'
url + '/preview'
end

MS_WORD_DOCUMENT_HUMANIZED_CONTENT_TYPE = "MS Word Document"
Expand Down Expand Up @@ -205,37 +235,52 @@ def humanized_content_type(file_extension)
end

def previewable?
attachment.csv?
file_extension == "csv"
end

def title
attachment.title
attachment[:title]
end

def file_extension
# Note: this is a separate parameter rather than being calculated from the
# filename because at the time of writing not all apps were using the effects
# of this field.
attachment[:file_extension]
end

def hide_thumbnail?
defined?(hide_thumbnail) && hide_thumbnail
end

def attachement_details
def attachment_details
return if previewable?
link(attachment.title, url, title_link_options)
link(title, url, title_link_options)
end

def title_link_options
title_link_options = ''
title_link_options << "rel=external" if attachment.external?
title_link_options << "aria-describedby=#{help_block_id}" unless attachment.accessible?
title_link_options = {}
title_link_options["rel"] = "external" if attachment[:external?]
title_link_options["aria-describedby"] = help_block_id unless attachment[:accessible?]
title_link_options
end

def help_block_id
"attachment-#{attachment.id}-accessibility-help"
"attachment-#{id}-accessibility-help"
end

def link(body, url, options={})
<<-END
<a href="#{url} #{options}">
#{body}
</a>
END
def link(body, url, options = {})
options_str = options.map { |k, v| %{#{encode(k)}="#{encode(v)}"} }.join(" ")
%{<a href="#{encode(url)}" #{options_str}>#{body}</a>}
end

private

def encode(text)
HTMLEntities.new.encode(text)
end

def urlencode(text)
ERB::Util.url_encode(text)
end
end
Loading