require 'cgi' module YARD module Templates::Helpers # The helper module for HTML templates. module HtmlHelper include MarkupHelper include HtmlSyntaxHighlightHelper # @group Escaping Template Data # Escapes HTML entities # # @param [String] text the text to escape # @return [String] the HTML with escaped entities def h(text) CGI.escapeHTML(text.to_s) end # Escapes a URL # # @param [String] text the URL # @return [String] the escaped URL def urlencode(text) CGI.escape(text.to_s) end # @group Converting Markup to HTML # Turns text into HTML using +markup+ style formatting. # # @param [String] text the text to format # @param [Symbol] markup examples are +:markdown+, +:textile+, +:rdoc+. # To add a custom markup type, see {MarkupHelper} # @return [String] the HTML def htmlify(text, markup = options.markup) markup_meth = "html_markup_#{markup}" return text unless respond_to?(markup_meth) return "" unless text return text unless markup html = send(markup_meth, text) if html.respond_to?(:encode) html = html.force_encoding(text.encoding) # for libs that mess with encoding html = html.encode(:invalid => :replace, :replace => '?') end html = resolve_links(html) unless [:text, :none, :pre].include?(markup) html = parse_codeblocks(html) end html end # Converts Markdown to HTML # @param [String] text input Markdown text # @return [String] output HTML # @since 0.6.0 def html_markup_markdown(text) # TODO: other libraries might be more complex provider = markup_class(:markdown) if provider.to_s == 'RDiscount' provider.new(text, :autolink).to_html elsif provider.to_s == 'RedcarpetCompat' provider.new(text, :no_intraemphasis, :gh_blockcode, :fenced_code, :autolink, :tables, :lax_spacing).to_html else provider.new(text).to_html end end # Converts Asciidoc to HTML # @param [String] text input Asciidoc text # @return [String] output HTML def html_markup_asciidoc(text) markup_class(:asciidoc).render(text) end # Converts Textile to HTML # @param [String] text the input Textile text # @return [String] output HTML # @since 0.6.0 def html_markup_textile(text) doc = markup_class(:textile).new(text) doc.hard_breaks = false if doc.respond_to?(:hard_breaks=) doc.to_html end # Converts plaintext to strict Textile (hard breaks) # @param [String] text the input textile data # @return [String] the output HTML # @since 0.6.0 def html_markup_textile_strict(text) markup_class(:textile).new(text).to_html end # Converts RDoc formatting (SimpleMarkup) to HTML # @param [String] text the input RDoc formatted text # @return [String] output HTML # @since 0.6.0 def html_markup_rdoc(text) doc = markup_class(:rdoc).new(text) doc.from_path = url_for(object) if doc.respond_to?(:from_path=) doc.to_html end # Converts plaintext to pre-formatted HTML # @param [String] text the input text # @return [String] the output HTML # @since 0.6.0 def html_markup_pre(text) "
" + h(text) + "" end # Converts plaintext to regular HTML # @param [String] text the input text # @return [String] the output HTML # @since 0.6.0 def html_markup_text(text) h(text).gsub(/\r?\n/, '
' + html_syntax_highlight(source, :ruby) + '' end # @return [String] HTMLified text as a single line (paragraphs removed) def htmlify_line(*args) "
|<\/p>\s*\Z/, '')
end
# (see BaseHelper#link_object)
def link_object(obj, title = nil, anchor = nil, relative = true)
return title if obj.nil?
obj = Registry.resolve(object, obj, true, true) if obj.is_a?(String)
if title
title = title.to_s
elsif object.is_a?(CodeObjects::Base)
# Check if we're linking to a class method in the current
# object. If we are, create a title in the format of
# "CurrentClass.method_name"
if obj.is_a?(CodeObjects::MethodObject) && obj.scope == :class && obj.parent == object
title = h([object.name, obj.sep, obj.name].join)
elsif obj.title != obj.path
title = h(obj.title)
else
title = h(object.relative_path(obj))
end
else
title = h(obj.title)
end
return title unless serializer
return title if obj.is_a?(CodeObjects::Proxy)
link = url_for(obj, anchor, relative)
link = link ? link_url(link, title, :title => h("#{obj.title} (#{obj.type})")) : title
"" + link + ""
end
# (see BaseHelper#link_url)
def link_url(url, title = nil, params = {})
title ||= url
title.gsub!(/[\r\n]/, ' ')
params = SymbolHash.new(false).update(
:href => url,
:title => h(title)
).update(params)
params[:target] ||= '_parent' if url =~ /^(\w+):\/\//
"#{title}".gsub(/[\r\n]/, ' ')
end
# @group URL Helpers
# @param [CodeObjects::Base] object the object to get an anchor for
# @return [String] the anchor for a specific object
def anchor_for(object)
case object
when CodeObjects::MethodObject
"#{object.name}-#{object.scope}_#{object.type}"
when CodeObjects::ClassVariableObject
"#{object.name.to_s.gsub('@@', '')}-#{object.type}"
when CodeObjects::Base
"#{object.name}-#{object.type}"
when CodeObjects::Proxy
object.path
else
object.to_s
end
end
# Returns the URL for an object.
#
# @param [String, CodeObjects::Base] obj the object (or object path) to link to
# @param [String] anchor the anchor to link to
# @param [Boolean] relative use a relative or absolute link
# @return [String] the URL location of the object
def url_for(obj, anchor = nil, relative = true)
link = nil
return link unless serializer
return link if obj.is_a?(CodeObjects::Base) && run_verifier([obj]).empty?
if obj.is_a?(CodeObjects::Base) && !obj.is_a?(CodeObjects::NamespaceObject)
# If the obj is not a namespace obj make it the anchor.
anchor, obj = obj, obj.namespace
end
objpath = serializer.serialized_path(obj)
return link unless objpath
relative = false if object == Registry.root
if relative
fromobj = object
if object.is_a?(CodeObjects::Base) &&
!object.is_a?(CodeObjects::NamespaceObject)
fromobj = owner
end
from = serializer.serialized_path(fromobj)
link = File.relative_path(from, objpath)
else
link = objpath
end
link + (anchor ? '#' + urlencode(anchor_for(anchor)) : '')
end
# Returns the URL for a specific file
#
# @param [String, CodeObjects::ExtraFileObject] filename the filename to link to
# @param [String] anchor optional anchor
# @return [String] the URL pointing to the file
def url_for_file(filename, anchor = nil)
return '' unless serializer
fromobj = object
if CodeObjects::Base === fromobj && !fromobj.is_a?(CodeObjects::NamespaceObject)
fromobj = fromobj.namespace
end
from = serializer.serialized_path(fromobj)
if filename == options.readme
path = 'index.html'
else
path = serializer.serialized_path(filename)
end
link = File.relative_path(from, path)
link += (anchor ? '#' + urlencode(anchor) : '')
link
end
# Returns the URL for a list type
#
# @param [String, Symbol] type the list type to generate a URL for
# @return [String] the URL pointing to the list
# @since 0.8.0
def url_for_list(type)
url_for_file("#{type}_list.html")
end
# Returns the URL for the frameset page
#
# @return [String] the URL pointing to the frames page
# @since 0.8.0
def url_for_frameset
url_for_file("frames.html")
end
# Returns the URL for the main page (README or alphabetic index)
#
# @return [String] the URL pointing to the first main page the
# user should see.
def url_for_main
url_for_file("index.html")
end
# Returns the URL for the alphabetic index page
#
# @return [String] the URL pointing to the first main page the
# user should see.
def url_for_index
url_for_file("_index.html")
end
# @group Formatting Objects and Attributes
# Formats a list of objects and links them
# @return [String] a formatted list of objects
def format_object_name_list(objects)
objects.sort_by {|o| o.name.to_s.downcase }.map do |o|
"" + linkify(o, o.name) + ""
end.join(", ")
end
# Formats a list of types from a tag.
#
# @param [Array(?:\s*
)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do
string = $3
# handle !!!LANG prefix to send to html_syntax_highlight_LANG
language, _ = parse_lang_for_codeblock(string)
language ||= $1 || $2 || object.source_type
if options.highlight
string = html_syntax_highlight(CGI.unescapeHTML(string), language)
end
classes = ['code', language].compact.join(' ')
%Q{
}
end
end
end
end
end
#{string}