2006-10-14 23:50:07 +00:00
|
|
|
module Haml
|
|
|
|
# This class is used only internally. It holds the buffer of XHTML that
|
|
|
|
# is eventually output by Haml::Engine's to_html method. It's called
|
|
|
|
# from within the precompiled code, and helps reduce the amount of
|
|
|
|
# processing done within instance_eval'd code.
|
|
|
|
class Buffer
|
|
|
|
include Haml::Helpers
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Set the maximum length for a line to be considered a one-liner.
|
|
|
|
# Lines <= the maximum will be rendered on one line,
|
|
|
|
# i.e. <tt><p>Hello world</p></tt>
|
|
|
|
ONE_LINER_LENGTH = 50
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# The string that holds the compiled XHTML. This is aliased as
|
|
|
|
# _erbout for compatibility with ERB-specific code.
|
|
|
|
attr_accessor :buffer
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-11-08 01:54:26 +00:00
|
|
|
# The number of tabs that are added or subtracted from the
|
|
|
|
# tabulation proscribed by the precompiled template.
|
|
|
|
attr_accessor :tabulation
|
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Creates a new buffer.
|
2006-10-27 21:20:19 +00:00
|
|
|
def initialize(options = {})
|
|
|
|
@options = options
|
2006-10-30 06:10:26 +00:00
|
|
|
@quote_escape = options[:attr_wrapper] == '"' ? """ : "'"
|
2006-10-14 23:50:07 +00:00
|
|
|
@buffer = ""
|
|
|
|
@one_liner_pending = false
|
2006-11-08 01:54:26 +00:00
|
|
|
@tabulation = 0
|
2006-10-14 23:50:07 +00:00
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Renders +text+ with the proper tabulation. This also deals with
|
|
|
|
# making a possible one-line tag one line or not.
|
2006-11-04 06:36:16 +00:00
|
|
|
def push_text(text, tabulation, flattened = false)
|
|
|
|
if flattened
|
|
|
|
# In this case, tabulation is the number of spaces, rather
|
|
|
|
# than the number of tabs.
|
|
|
|
@buffer << "#{' ' * tabulation}#{flatten(text + "\n")}"
|
|
|
|
@one_liner_pending = true
|
|
|
|
elsif @one_liner_pending && one_liner?(text)
|
2006-10-14 23:50:07 +00:00
|
|
|
@buffer << text
|
|
|
|
else
|
|
|
|
if @one_liner_pending
|
|
|
|
@buffer << "\n"
|
|
|
|
@one_liner_pending = false
|
|
|
|
end
|
|
|
|
@buffer << "#{tabs(tabulation)}#{text}\n"
|
|
|
|
end
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Properly formats the output of a script that was run in the
|
|
|
|
# instance_eval.
|
|
|
|
def push_script(result, tabulation, flattened)
|
|
|
|
if flattened
|
|
|
|
result = find_and_flatten(result)
|
|
|
|
end
|
|
|
|
unless result.nil?
|
|
|
|
result = result.to_s.chomp.gsub("\n", "\n#{tabs(tabulation)}")
|
|
|
|
push_text result, tabulation
|
|
|
|
end
|
|
|
|
nil
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Takes the various information about the opening tag for an
|
|
|
|
# element, formats it, and adds it to the buffer.
|
2006-11-04 06:36:16 +00:00
|
|
|
def open_tag(name, tabulation, atomic, try_one_line, class_id, attributes_hash, obj_ref, flattened)
|
2006-10-14 23:50:07 +00:00
|
|
|
attributes = {}
|
|
|
|
attributes.merge!(parse_object_ref(obj_ref)) if obj_ref
|
|
|
|
attributes.merge!(parse_class_and_id(class_id)) if class_id
|
|
|
|
attributes.merge!(attributes_hash) unless attributes_hash.nil? || attributes_hash.empty?
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
@buffer << "#{tabs(tabulation)}<#{name}#{build_attributes(attributes)}"
|
|
|
|
@one_liner_pending = false
|
|
|
|
if atomic
|
|
|
|
@buffer << " />\n"
|
2006-11-04 06:36:16 +00:00
|
|
|
elsif try_one_line
|
|
|
|
@one_liner_pending = true
|
|
|
|
@buffer << ">"
|
|
|
|
elsif flattened
|
|
|
|
@buffer << ">
"
|
2006-10-14 23:50:07 +00:00
|
|
|
else
|
2006-11-04 06:36:16 +00:00
|
|
|
@buffer << ">\n"
|
2006-10-14 23:50:07 +00:00
|
|
|
end
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Creates a closing tag with the given name.
|
|
|
|
def close_tag(name, tabulation)
|
|
|
|
if @one_liner_pending
|
|
|
|
@buffer << "</#{name}>\n"
|
|
|
|
@one_liner_pending = false
|
|
|
|
else
|
|
|
|
push_text("</#{name}>", tabulation)
|
|
|
|
end
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-22 21:42:45 +00:00
|
|
|
# Opens an XHTML comment.
|
|
|
|
def open_comment(try_one_line, conditional, tabulation)
|
|
|
|
conditional << ">" if conditional
|
|
|
|
@buffer << "#{tabs(tabulation)}<!--#{conditional.to_s} "
|
|
|
|
if try_one_line
|
|
|
|
@one_liner_pending = true
|
|
|
|
else
|
|
|
|
@buffer << "\n"
|
|
|
|
end
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-22 21:42:45 +00:00
|
|
|
# Closes an XHTML comment.
|
|
|
|
def close_comment(has_conditional, tabulation)
|
|
|
|
close_tag = has_conditional ? "<![endif]-->" : "-->"
|
|
|
|
if @one_liner_pending
|
|
|
|
@buffer << " #{close_tag}\n"
|
|
|
|
@one_liner_pending = false
|
|
|
|
else
|
|
|
|
push_text(close_tag, tabulation)
|
|
|
|
end
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
private
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Gets <tt>count</tt> tabs. Mostly for internal use.
|
|
|
|
def tabs(count)
|
2006-11-08 01:54:26 +00:00
|
|
|
' ' * (count + @tabulation)
|
2006-10-14 23:50:07 +00:00
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Iterates through the classes and ids supplied through <tt>.</tt>
|
|
|
|
# and <tt>#</tt> syntax, and returns a hash with them as attributes,
|
|
|
|
# that can then be merged with another attributes hash.
|
|
|
|
def parse_class_and_id(list)
|
|
|
|
attributes = {}
|
2006-10-30 05:24:28 +00:00
|
|
|
list.scan(/([#.])([-_a-zA-Z0-9]+)/) do |type, property|
|
2006-10-14 23:50:07 +00:00
|
|
|
case type
|
|
|
|
when '.'
|
|
|
|
if attributes[:class]
|
|
|
|
attributes[:class] += " "
|
|
|
|
else
|
|
|
|
attributes[:class] = ""
|
|
|
|
end
|
|
|
|
attributes[:class] += property
|
|
|
|
when '#'
|
|
|
|
attributes[:id] = property
|
|
|
|
end
|
|
|
|
end
|
|
|
|
attributes
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Takes an array of objects and uses the class and id of the first
|
|
|
|
# one to create an attributes hash.
|
|
|
|
def parse_object_ref(ref)
|
|
|
|
ref = ref[0]
|
2006-11-06 02:23:32 +00:00
|
|
|
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
|
|
|
return {} if ref.nil?
|
2006-10-14 23:50:07 +00:00
|
|
|
class_name = ref.class.to_s.underscore
|
|
|
|
{:id => "#{class_name}_#{ref.id}", :class => class_name}
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Takes a hash and builds a list of XHTML attributes from it, returning
|
|
|
|
# the result.
|
|
|
|
def build_attributes(attributes = {})
|
2006-10-20 02:38:53 +00:00
|
|
|
attributes.each do |key, value|
|
|
|
|
unless key.is_a? String
|
|
|
|
attributes.delete key
|
|
|
|
attributes[key.to_s] = value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
result = attributes.sort.collect do |a,v|
|
2006-10-14 23:50:07 +00:00
|
|
|
unless v.nil?
|
2006-10-30 06:10:26 +00:00
|
|
|
v = v.to_s
|
|
|
|
attr_wrapper = @options[:attr_wrapper]
|
|
|
|
if v.include? attr_wrapper
|
|
|
|
v = v.gsub(attr_wrapper, @quote_escape)
|
|
|
|
end
|
|
|
|
"#{a.to_s}=#{attr_wrapper}#{v}#{attr_wrapper}"
|
2006-10-14 23:50:07 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
result = result.compact.join(' ')
|
|
|
|
(attributes.empty? ? String.new : String.new(' ')) + result
|
|
|
|
end
|
2006-11-04 06:36:16 +00:00
|
|
|
|
2006-10-14 23:50:07 +00:00
|
|
|
# Returns whether or not the given value is short enough to be rendered
|
|
|
|
# on one line.
|
|
|
|
def one_liner?(value)
|
|
|
|
value.length <= ONE_LINER_LENGTH && value.scan(/\n/).empty?
|
|
|
|
end
|
2006-11-06 03:01:04 +00:00
|
|
|
|
|
|
|
# Isolates the whitespace-sensitive tags in the string and uses Haml::Helpers#flatten
|
|
|
|
# to convert any endlines inside them into html entities.
|
|
|
|
def find_and_flatten(input)
|
|
|
|
input.scan(/<(textarea|code|pre)[^>]*>(.*?)<\/\1>/im).each do |thing|
|
|
|
|
input = input.gsub(thing[1], Haml::Helpers.flatten(thing[1]))
|
|
|
|
end
|
|
|
|
input
|
|
|
|
end
|
2006-10-14 23:50:07 +00:00
|
|
|
end
|
|
|
|
end
|