# -*- encoding: utf-8 -*-
require 'erb'
module Webgen
class ContentProcessor
# == General information
#
# Inserts additional links to CSS/JS files and other HTML head meta info directly before the
# HTML head end tag.
#
# The data used by this content processor is taken from the Context object. Therefore this
# processor should be the last in the processing pipeline so that all other processors have been
# able to set the data.
#
# Use the methods defined on the special Webgen::Context::HtmlHead::Proxy object which can be
# accessed via Webgen::Context#html_head to provide values.
#
# == Internal details
#
# The key +:cp_html_head+ of +context.persistent+ is used (the normal +context.options+ won't do
# because the data needs to be shared 'backwards' during the rendering) and it has to be a Hash
# with the following values:
#
# [:js_file] An array of already resolved relative or absolute paths to Javascript files.
# [:js_inline] An array of Javascript fragments to be inserted directly into the head section.
# [:css_file] An array of already resolved relative or absolute paths to CSS files.
# [:css_inline] An array of CSS fragments to be inserted directly into the head section.
# [:meta] A hash with key-value pairs from which 'meta' tags are generated. The keys and the
# values will be properly escaped before insertion. The entries in the meta information
# 'meta' of the content node are also used and take precedence over these entries.
#
# Duplicate values will be removed from the above mentioned arrays before generating the output.
#
module HtmlHead
HTML_HEAD_END_RE = /<\/head\s*>/i #:nodoc:
# Insert the additional header information.
def self.call(context)
context.content.sub!(HTML_HEAD_END_RE) do |match|
result = ''
result << tags_from_context_data(context)
result << links_to_translations(context)
result << links_from_link_meta_info(context)
result << match
end
context
end
# Return a string containing the HTML tags corresponding to the information set in the given
# Context object and the values of the meta info key +meta+ of the content node.
def self.tags_from_context_data(context)
result = ''
if context.persistent[:cp_html_head].kind_of?(Hash)
process_data_array(context, :js_file) do |js_file|
result += "\n"
end
process_data_array(context, :js_inline) do |content|
result += "\n"
end
process_data_array(context, :css_file) do |css_file|
result += "\n"
end
process_data_array(context, :css_inline) do |content|
result += "\n"
end
end
((context.persistent[:cp_html_head] || {})[:meta] || {}).merge(context.content_node['meta'] || {}).each do |name, content|
result += "\n"
end
((context.persistent[:cp_html_head] || {})[:meta_property] || {}).merge(context.content_node['meta_property'] || {}).each do |property, content|
result += "\n"
end
result
end
# Yield the values of the specified array.
def self.process_data_array(context, array_name, &block)
(context.persistent[:cp_html_head][array_name] || []).uniq.each(&block)
end
# Return a string containing HTML link tags to translations of the destination node.
def self.links_to_translations(context)
context.website.tree.translations(context.dest_node).map do |node|
next '' if node.alcn == context.dest_node.alcn
context.website.ext.item_tracker.add(context.dest_node, :node_meta_info, node)
result = "\n"
end.join('')
end
# Given an array of path names, add tracker information for the resolved nodes (reference node
# is the content node) and return the relative paths to them.
def self.resolve_paths(context, paths)
[paths].flatten.compact.collect do |path|
next path if Webgen::Path.url(path, false).absolute?
node = context.content_node.resolve(path, context.dest_node.lang, true)
if node
context.website.ext.item_tracker.add(context.dest_node, :node_meta_info, node)
context.dest_node.route_to(node)
else
nil
end
end.compact
end
LINK_DOCUMENT_ATTRS = {'type' => 'text/html'} #:nodoc:
LINK_DOCUMENT_TYPES = %w{start next prev contents index glossary chapter section subsection appendix help} #:nodoc:
# Return a string containing HTML link tags to the links from the 'link' meta information.
def self.links_from_link_meta_info(context)
link_mi = Marshal.load(Marshal.dump(context.content_node['link'] || {}))
result = ''
# Add user defined javascript and CSS links
resolve_paths(context, link_mi.delete('javascript')).each do |file|
result += "\n"
end
resolve_paths(context, link_mi.delete('css')).each do |file|
result += "\n"
end
# add generic links
link_mi.sort.each do |link_type, vals|
link_type = link_type.downcase
[vals].flatten.each do |val|
val = {'href' => val} if val.kind_of?(String)
val['rel'] ||= link_type
val = LINK_DOCUMENT_ATTRS.merge(val) if LINK_DOCUMENT_TYPES.include?(link_type)
href = val.delete('href')
href = resolve_paths(context, href).first if href
if href
result << "\n"
else
context.website.logger.error do
"No link target specified for link type '#{link_type}' in 'link' meta information in <#{context.content_node}>"
end
end
end
end
result
end
end
end
end