module Temple module HTML # @api public class Pretty < Fast set_default_options :indent => ' ', :pretty => true, :indent_tags => %w(article aside audio base body datalist dd div dl dt fieldset figure footer form head h1 h2 h3 h4 h5 h6 header hgroup hr html input li link meta nav ol p rp rt ruby section script style table tbody td tfoot th thead title tr ul video).freeze, :pre_tags => %w(code pre textarea).freeze def initialize(opts = {}) super @last = :noindent @indent = 0 @pretty = options[:pretty] @pre_tags = Regexp.new(options[:pre_tags].map {|t| "<#{t}" }.join('|')) end def call(exp) @pretty ? [:multi, preamble, compile(exp)] : super end def on_static(content) if @pretty content = content.gsub("\n", indent) if @pre_tags !~ content @last = content.sub!(/\r?\n\s*$/, ' ') ? nil : :noindent end [:static, content] end def on_dynamic(code) if @pretty @last = :noindent tmp = unique_name gsub_code = if ''.respond_to?(:html_safe?) "#{tmp} = #{tmp}.html_safe? ? #{tmp}.gsub(\"\\n\", #{indent.inspect}).html_safe : #{tmp}.gsub(\"\\n\", #{indent.inspect})" else "#{tmp} = #{tmp}.gsub(\"\\n\", #{indent.inspect})" end [:multi, [:code, "#{tmp} = (#{code}).to_s"], [:code, "if #{@pre_tags_name} !~ #{tmp}; #{gsub_code}; end"], [:dynamic, tmp]] else [:dynamic, code] end end def on_html_doctype(type) @last = nil super end def on_html_comment(content) return super unless @pretty result = [:multi, [:static, tag_indent(nil)], super] @last = nil result end def on_html_tag(name, attrs, content = nil) return super unless @pretty name = name.to_s closed = !content || (empty_exp?(content) && options[:autoclose].include?(name)) @pretty = false result = [:multi, [:static, "#{tag_indent(name)}<#{name}"], compile(attrs)] result << [:static, (closed && xhtml? ? ' /' : '') + '>'] @pretty = !options[:pre_tags].include?(name) if content @indent += 1 result << compile(content) @indent -= 1 end result << [:static, "#{content && !empty_exp?(content) ? tag_indent(name) : ''}</#{name}>"] unless closed @pretty = true result end protected def preamble @pre_tags_name = unique_name [:code, "#{@pre_tags_name} = /#{@pre_tags.source}/"] end # Return indentation if not in pre tag def indent "\n" + (options[:indent] || '') * @indent end # Return indentation before tag def tag_indent(name) result = @last != :noindent && (options[:indent_tags].include?(@last) || options[:indent_tags].include?(name)) ? indent : '' @last = name result end end end end