completely get rid of old layouts + enhance snippets integration + refactor parsing page module
This commit is contained in:
parent
dbc542c4d7
commit
9d78a32340
40
app/models/extensions/page/parse.rb
Normal file
40
app/models/extensions/page/parse.rb
Normal file
@ -0,0 +1,40 @@
|
||||
module Models
|
||||
module Extensions
|
||||
module Page
|
||||
module Parse
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
field :serialized_template, :type => Binary
|
||||
|
||||
before_validation :serialize_template
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def template
|
||||
@template ||= Marshal.load(read_attribute(:serialized_template).to_s) rescue nil
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def serialize_template
|
||||
if self.new_record? || self.raw_template_changed?
|
||||
begin
|
||||
@template = ::Liquid::Template.parse(self.raw_template, { :site => self.site })
|
||||
@template.root.context.clear
|
||||
|
||||
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
||||
rescue ::Liquid::SyntaxError => error
|
||||
self.errors.add :template, :liquid_syntax_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,32 +0,0 @@
|
||||
class LiquidTemplate
|
||||
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :slug
|
||||
field :value
|
||||
|
||||
## associations ##
|
||||
referenced_in :site
|
||||
|
||||
## callbacks ##
|
||||
before_validation :normalize_slug
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :site, :name, :slug, :value
|
||||
validates_uniqueness_of :slug, :scope => :site_id
|
||||
|
||||
## behaviours ##
|
||||
liquify_template :value
|
||||
|
||||
## methods ##
|
||||
|
||||
protected
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify!(:without_extension => true, :downcase => true) if self.slug.present?
|
||||
end
|
||||
|
||||
end
|
@ -5,6 +5,7 @@ class Page
|
||||
## Extensions ##
|
||||
include Models::Extensions::Page::Tree
|
||||
# include Models::Extensions::Page::Parts
|
||||
include Models::Extensions::Page::Parse
|
||||
include Models::Extensions::Page::Render
|
||||
include Models::Extensions::Page::Templatized
|
||||
|
||||
@ -12,11 +13,10 @@ class Page
|
||||
field :title
|
||||
field :slug
|
||||
field :fullpath
|
||||
field :raw_template
|
||||
field :published, :type => Boolean, :default => false
|
||||
field :cache_strategy, :default => 'none'
|
||||
|
||||
field :layout_template # FIXME: added for liquid inheritance
|
||||
|
||||
## associations ##
|
||||
referenced_in :site
|
||||
|
||||
@ -36,10 +36,6 @@ class Page
|
||||
scope :not_found, :where => { :slug => '404', :depth => 0 }
|
||||
scope :published, :where => { :published => true }
|
||||
|
||||
## behaviours ##
|
||||
# liquify_template :joined_parts
|
||||
liquify_template :layout_template
|
||||
|
||||
## methods ##
|
||||
|
||||
def index?
|
||||
|
@ -83,7 +83,7 @@ class Site
|
||||
self.pages.create({
|
||||
:slug => slug,
|
||||
:title => I18n.t("attributes.defaults.pages.#{slug}.title"),
|
||||
:layout_template => I18n.t("attributes.defaults.pages.#{slug}.body"),
|
||||
:raw_template => I18n.t("attributes.defaults.pages.#{slug}.body"),
|
||||
:published => true
|
||||
})
|
||||
end
|
||||
|
@ -1,3 +1,30 @@
|
||||
class Snippet < LiquidTemplate
|
||||
class Snippet
|
||||
|
||||
include Locomotive::Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :name
|
||||
field :slug
|
||||
field :template
|
||||
|
||||
## associations ##
|
||||
referenced_in :site
|
||||
|
||||
## callbacks ##
|
||||
before_validation :normalize_slug
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :site, :name, :slug, :template
|
||||
validates_uniqueness_of :slug, :scope => :site_id
|
||||
|
||||
## methods ##
|
||||
|
||||
protected
|
||||
|
||||
def normalize_slug
|
||||
self.slug = self.name.clone if self.slug.blank? && self.name.present?
|
||||
self.slug.slugify!(:without_extension => true, :downcase => true) if self.slug.present?
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -21,11 +21,11 @@
|
||||
|
||||
= f.input :cache_strategy, :as => :select, :collection => options_for_page_cache_strategy, :include_blank => false
|
||||
|
||||
= f.foldable_inputs :name => :layout_template do
|
||||
= f.foldable_inputs :name => :raw_template do
|
||||
= f.custom_input :value, :css => 'code full', :with_label => false do
|
||||
= f.label :layout_template
|
||||
= f.label :raw_template
|
||||
%code{ :class => 'html' }
|
||||
= f.text_area :layout_template
|
||||
= f.text_area :raw_template
|
||||
/ .more
|
||||
/ = link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
= f.input :slug, :required => false
|
||||
|
||||
= f.inputs :name => :code do
|
||||
= f.custom_input :value, :css => 'full', :with_label => false do
|
||||
= f.custom_input :template, :css => 'full', :with_label => false do
|
||||
%code{ :class => 'html' }
|
||||
= f.text_area :value
|
||||
= f.text_area :template
|
||||
.more
|
||||
= link_to t('admin.image_picker.link'), admin_theme_assets_path, :id => 'image-picker-link'
|
@ -245,7 +245,7 @@ en:
|
||||
information: General information
|
||||
meta: SEO Metadata
|
||||
code: Code
|
||||
layout_template: Layout
|
||||
raw_template: Layout
|
||||
credentials: Credentials
|
||||
language: Language
|
||||
sites: Sites
|
||||
|
@ -244,7 +244,7 @@ fr:
|
||||
information: Informations générales
|
||||
meta: SEO Metadata
|
||||
code: Code
|
||||
layout_template: Gabarit
|
||||
raw_template: Gabarit
|
||||
credentials: Informations de connexion
|
||||
language: Langue
|
||||
sites: Sites
|
||||
|
@ -1,4 +1,4 @@
|
||||
Feature: Engine
|
||||
Feature: Inheritance
|
||||
As a designer
|
||||
I want to be able to build more complex page html layouts
|
||||
with shared template code
|
||||
|
21
features/engine/snippets.feature
Normal file
21
features/engine/snippets.feature
Normal file
@ -0,0 +1,21 @@
|
||||
Feature: Snippets
|
||||
As a designer
|
||||
I want to insert re-usable piece of code among pages
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And a snippet named "yield" with the template:
|
||||
"""
|
||||
HELLO WORLD !
|
||||
"""
|
||||
|
||||
Scenario: Simple include
|
||||
Given a page named "hello-world" with the template:
|
||||
"""
|
||||
My application says {% include 'yield' %}
|
||||
"""
|
||||
When I view the rendered page at "/hello-world"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
My application says HELLO WORLD !
|
||||
"""
|
@ -27,13 +27,3 @@ end
|
||||
|
||||
### Common
|
||||
|
||||
# def create_layout_samples
|
||||
# Factory(:layout, :site => @site, :name => 'One column', :value => %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="main">{{ content_for_layout }}</div>
|
||||
# </body>
|
||||
# </html>})
|
||||
# end
|
||||
|
@ -1,9 +1,9 @@
|
||||
### Pages
|
||||
|
||||
# helps create a simple content page (parent: "index") with a slug, contents, and layout
|
||||
# helps create a simple content page (parent: "index") with a slug, contents, and template
|
||||
def create_content_page(page_slug, page_contents, template = nil)
|
||||
@home = @site.pages.where(:slug => "index").first || Factory(:page)
|
||||
page = @site.pages.create(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :layout_template => template)
|
||||
page = @site.pages.create(:slug => page_slug, :body => page_contents, :parent => @home, :title => "some title", :published => true, :raw_template => template)
|
||||
page.should be_valid
|
||||
page
|
||||
end
|
||||
@ -46,7 +46,7 @@ Then /^I should have "(.*)" in the (.*) page$/ do |content, page_slug|
|
||||
page = @site.pages.where(:slug => page_slug).first
|
||||
raise "Could not find page: #{page_slug}" unless page
|
||||
|
||||
page.layout_template.should == content
|
||||
page.raw_template.should == content
|
||||
end
|
||||
|
||||
# checks if the rendered body matches a string
|
||||
|
16
features/step_definitions/snippet_steps.rb
Normal file
16
features/step_definitions/snippet_steps.rb
Normal file
@ -0,0 +1,16 @@
|
||||
### Snippets
|
||||
|
||||
# helps create a simple snippet with a slug and template
|
||||
def create_snippet(name, template = nil)
|
||||
snippet = @site.snippets.create(:name => name, :template => template)
|
||||
snippet.should be_valid
|
||||
snippet
|
||||
end
|
||||
|
||||
# creates a snippet
|
||||
|
||||
Given /^a snippet named "([^"]*)" with the template:$/ do |name, template|
|
||||
@snippet = create_snippet(name, template)
|
||||
end
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
%w{. tags drops filters}.each do |dir|
|
||||
Dir[File.join(File.dirname(__FILE__), 'liquid', dir, '*.rb')].each { |lib| require lib }
|
||||
end
|
||||
|
||||
::Liquid::Template.file_system = Locomotive::Liquid::DbFileSystem.new # enable snippets
|
||||
|
@ -1,18 +0,0 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
class DbFileSystem
|
||||
|
||||
# Works only with snippets
|
||||
def read_template_file(site, template_path)
|
||||
raise FileSystemError, "Illegal snippet name '#{template_path}'" unless template_path =~ /^[^.\/][a-zA-Z0-9_\/]+$/
|
||||
|
||||
snippet = site.snippets.where(:slug => template_path).first
|
||||
|
||||
raise FileSystemError, "No such snippet '#{template_path}'" if snippet.nil?
|
||||
|
||||
snippet.template
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,66 +0,0 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
module LiquifyTemplate
|
||||
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
# Store the parsed version of a liquid template into a column in order to increase performance
|
||||
# See http://cjohansen.no/en/rails/liquid_email_templates_in_rails
|
||||
#
|
||||
# class Page
|
||||
# liquify_template :body
|
||||
# end
|
||||
#
|
||||
# page = Page.new :body => '...some liquid tags'
|
||||
# page.template # Liquid::Template
|
||||
#
|
||||
#
|
||||
module ClassMethods
|
||||
|
||||
def liquify_template(source = :value)
|
||||
field :serialized_template, :type => Binary
|
||||
before_validation :store_template
|
||||
|
||||
class_eval <<-EOV
|
||||
def liquify_template_source
|
||||
self.send(:#{source.to_s})
|
||||
end
|
||||
EOV
|
||||
|
||||
include InstanceMethods
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def template
|
||||
@template ||= Marshal.load(read_attribute(:serialized_template).to_s) rescue nil
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def store_template
|
||||
begin
|
||||
# puts "self.liquify_template_source = #{self.liquify_template_source.inspect}"
|
||||
@template = ::Liquid::Template.parse(self.liquify_template_source, { :site => self.site })
|
||||
@template.root.context.clear
|
||||
# puts "@template = #{@template.inspect}"
|
||||
# @template = Locomotive::Liquid::Template.parse(self)
|
||||
|
||||
if self.respond_to?(:after_parse_template) # kind of callback
|
||||
self.send(:after_parse_template)
|
||||
end
|
||||
|
||||
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
||||
rescue ::Liquid::SyntaxError => error
|
||||
self.errors.add :template, :liquid_syntax_error
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -4,10 +4,21 @@ module Locomotive
|
||||
|
||||
class Snippet < ::Liquid::Include
|
||||
|
||||
def render(context)
|
||||
site = context.registers[:site]
|
||||
attr_accessor :partial
|
||||
|
||||
partial = ::Liquid::Template.file_system.read_template_file(site, context[@template_name])
|
||||
def initialize(tag_name, markup, tokens, context)
|
||||
super
|
||||
|
||||
snippet = context[:site].snippets.where(:slug => @template_name.gsub('\'', '')).first
|
||||
|
||||
if snippet
|
||||
@partial = ::Liquid::Template.parse(snippet.template, context)
|
||||
@partial.root.context.clear
|
||||
end
|
||||
end
|
||||
|
||||
def render(context)
|
||||
return '' if @partial.nil?
|
||||
|
||||
variable = context[@variable_name || @template_name[1..-2]]
|
||||
|
||||
@ -19,11 +30,11 @@ module Locomotive
|
||||
output = (if variable.is_a?(Array)
|
||||
variable.collect do |variable|
|
||||
context[@template_name[1..-2]] = variable
|
||||
partial.render(context)
|
||||
@partial.render(context)
|
||||
end
|
||||
else
|
||||
context[@template_name[1..-2]] = variable
|
||||
partial.render(context)
|
||||
@partial.render(context)
|
||||
end)
|
||||
|
||||
output
|
||||
|
@ -10,7 +10,6 @@ module Locomotive
|
||||
include ::Mongoid::Document
|
||||
include ::Mongoid::Timestamps
|
||||
include ::Mongoid::CustomFields
|
||||
include Locomotive::Liquid::LiquifyTemplate
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -11,7 +11,7 @@ puts "Starting test..."
|
||||
|
||||
site = Site.create :name => 'Benchmark Website', :subdomain => 'benchmark'
|
||||
|
||||
simple = site.pages.create :title => 'Simple', :slug => 'simple', :layout_template => %{
|
||||
simple = site.pages.create :title => 'Simple', :slug => 'simple', :raw_template => %{
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
@ -29,7 +29,7 @@ simple = site.pages.create :title => 'Simple', :slug => 'simple', :layout_templa
|
||||
</html>
|
||||
}
|
||||
|
||||
base = site.pages.create :title => 'Base page', :slug => 'base', :layout_template => %{
|
||||
base = site.pages.create :title => 'Base page', :slug => 'base', :raw_template => %{
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
@ -47,13 +47,13 @@ base = site.pages.create :title => 'Base page', :slug => 'base', :layout_templat
|
||||
</html>
|
||||
}
|
||||
|
||||
page_1 = site.pages.create :title => 'Page 1', :slug => 'page_1', :layout_template => %{
|
||||
page_1 = site.pages.create :title => 'Page 1', :slug => 'page_1', :raw_template => %{
|
||||
{% extends base %}
|
||||
{% block sidebar %}A sidebar here{% endblock %}
|
||||
{% block body %}<div class="wrapper">{% block main %}DEFAULT MAIN CONTENT{% endblock %}</div>{% endblock %}
|
||||
}
|
||||
|
||||
page_2 = site.pages.create :title => 'Page 2', :slug => 'page_2', :layout_template => %{
|
||||
page_2 = site.pages.create :title => 'Page 2', :slug => 'page_2', :raw_template => %{
|
||||
{% extends page_1 %}
|
||||
{% block sidebar %}{{ block.super }} / INDEX sidebar{% endblock %}
|
||||
{% block main %}Lorem ipsum{% endblock %}
|
||||
|
@ -56,59 +56,11 @@ Factory.define :page do |p|
|
||||
end
|
||||
|
||||
|
||||
# Factory.define "unpub"
|
||||
|
||||
## Liquid templates ##
|
||||
Factory.define :liquid_template do |t|
|
||||
t.name 'Simple one'
|
||||
t.slug 'simple_one'
|
||||
t.value %{simple liquid template}
|
||||
t.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||
end
|
||||
|
||||
|
||||
# ## Layouts ##
|
||||
# Factory.define :layout do |l|
|
||||
# l.name '1 main column + sidebar'
|
||||
# l.value %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="sidebar">
|
||||
# \{% block sidebar %\}
|
||||
# DEFAULT SIDEBAR CONTENT
|
||||
# \{% endblock %\}
|
||||
# </div>
|
||||
# <div id="main">
|
||||
# \{% block main %\}
|
||||
# DEFAULT MAIN CONTENT
|
||||
# \{% endblock %\}
|
||||
# </div>
|
||||
# </body>
|
||||
# </html>}
|
||||
# l.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||
# end
|
||||
#
|
||||
# Factory.define :base_layout, :parent => :layout do |l|
|
||||
# l.name '1 main column + sidebar'
|
||||
# l.value %{<html>
|
||||
# <head>
|
||||
# <title>My website</title>
|
||||
# </head>
|
||||
# <body>
|
||||
# <div id="sidebar">\{\{ content_for_left_sidebar \}\}</div>
|
||||
# <div id="main">\{\{ content_for_layout | textile \}\}</div>
|
||||
# </body>
|
||||
# </html>}
|
||||
# end
|
||||
|
||||
|
||||
## Snippets ##
|
||||
Factory.define :snippet do |s|
|
||||
s.name 'My website title'
|
||||
s.slug 'header'
|
||||
s.value %{<title>Acme</title>}
|
||||
s.template %{<title>Acme</title>}
|
||||
s.site { Site.where(:subdomain => "acme").first || Factory(:site) }
|
||||
end
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Tags::Snippet do
|
||||
|
||||
before(:each) do
|
||||
Site.any_instance.stubs(:create_default_pages!).returns(true)
|
||||
site = Factory.build(:site)
|
||||
snippet = Factory.build(:snippet, :site => site)
|
||||
snippet.send(:store_template)
|
||||
site.snippets.stubs(:where).returns([snippet])
|
||||
@context = ::Liquid::Context.new({}, {}, { :site => site })
|
||||
end
|
||||
|
||||
it 'should render it' do
|
||||
template = ::Liquid::Template.parse("{% include 'header' %}")
|
||||
text = template.render(@context)
|
||||
text.should == "<title>Acme</title>"
|
||||
end
|
||||
|
||||
end
|
@ -1,19 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe LiquidTemplate do
|
||||
|
||||
it 'should have a valid factory' do
|
||||
Factory.build(:liquid_template).should be_valid
|
||||
end
|
||||
|
||||
# Validations ##
|
||||
|
||||
%w{site name value}.each do |field|
|
||||
it "should validate presence of #{field}" do
|
||||
template = Factory.build(:liquid_template, field.to_sym => nil)
|
||||
template.should_not be_valid
|
||||
template.errors[field.to_sym].should == ["can't be blank"]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -6,4 +6,14 @@ describe Snippet do
|
||||
Factory.build(:snippet).should be_valid
|
||||
end
|
||||
|
||||
# Validations ##
|
||||
|
||||
%w{site name template}.each do |field|
|
||||
it "should validate presence of #{field}" do
|
||||
template = Factory.build(:snippet, field.to_sym => nil)
|
||||
template.should_not be_valid
|
||||
template.errors[field.to_sym].should == ["can't be blank"]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user