# main class for HAML template rendering require 'haml' class HamlTemplate < BaseDrop include UrlFilters include DropFilters include CoreFilters def initialize(site) @site_source = site @@precompiled_templates ||= {} end def liquify(*records, &block) self.class.liquify(@context, *records, &block) end def render(section, layout, template, assigns ={}, controller = nil) @layout = layout @template = template @controller = controller @assigns = assigns # psq-TODO: assigns contains mode, site, articles, section (more or less depending on mode, # consider using missing method to expose all of them to templates) # "section" would be nicer than # "@assigns['section']" @context = ::Liquid::Context.new(assigns, {}, false) # assigns, register, rethrow error @mode = assigns['mode'] @archive_date = assigns['archive_date'] @articles = assigns['articles'] @articles.each { |article| article.context = @context } if (@articles) @article = assigns['article'] @article.context = @context if @article # form handling @submitted = @context['submitted'] || {} @submitted.each{ |k, v| @submitted[k] = CGI::escapeHTML(v) } @errors = @context['errors'] @message = @context['message'] @site = @site_source.to_liquid(section) @site.context = @context if (section) @section = section.to_liquid @section.context = @context end @locals = { :mode => @mode, :controller => @controller, :archive_date => @archive_date, :articles => @articles, :article => @article, :submitted => @submitted, :site => @site, :section => @section} to_html end # entry point for rendering layout and main_template to html # not reentrant at this point because of the use of @ouput and @binding def to_html @binding = get_binding #use the same binding throughout do_include(@layout) end # # in layout, include content using chosen template # <% main_content %> # def main_content do_include(@template, context={}) end # include template # <% include "template name" %> def include(template, context={}) do_include(@site_source.find_preferred_template(:page, template+".haml"), context) end def random_articles(section, limit = nil) liquify(*section.source.articles.find(:all, :order => 'RAND()', :limit => (limit || section.source.articles_per_page))) end protected def do_include(template, context={}) # need to save/restore @output since everything is using the same binding. # psq-TODO: if page caching is not working well enough, keeping a compiled version of the template could help # see ActionView::CompiledTemplates begin options = {} # options[:locals] = @locals.merge(context) options[:filename] ||= template # Precompiling is automatic in this version of Haml # if @precompiled = get_precompiled(template) # options[:precompiled] ||= @precompiled # engine = Haml::Engine.new("", options) # else engine = Haml::Engine.new(File.read(template), options) # set_precompiled(template, engine.precompiled) # end engine.to_html(self, @locals.merge(context)) rescue raise "HAML Error: #{$!}" end end def get_binding binding end # Gets the cached, precompiled version of the template at location filename # as a string. def get_precompiled(filename) # Do we have it on file? Is it new enough? if (precompiled, precompiled_on = @@precompiled_templates[filename]) && (precompiled_on == File.mtime(filename).to_i) precompiled end end # Sets the cached, precompiled version of the template at location filename # to precompiled. def set_precompiled(filename, precompiled) @@precompiled_templates[filename] = [precompiled, File.mtime(filename).to_i] end end