implementation of editable_short_text in progress (tests failed)
This commit is contained in:
parent
e580021eda
commit
be36c85e90
2
Gemfile
2
Gemfile
@ -3,7 +3,7 @@ source 'http://rubygems.org'
|
||||
|
||||
gem 'rails', '3.0.0.rc'
|
||||
|
||||
gem 'liquid', :git => 'git://github.com/locomotivecms/liquid.git', :ref => 'a41213c77cbc81dab87d'
|
||||
gem 'liquid', :git => 'git://github.com/locomotivecms/liquid.git', :ref => 'dbcc0b1d9c189b3e3a13'
|
||||
|
||||
gem 'bson_ext', '>= 1.0.1'
|
||||
gem 'mongoid', '2.0.0.beta.16'
|
||||
|
20
Gemfile.lock
20
Gemfile.lock
@ -1,8 +1,8 @@
|
||||
GIT
|
||||
remote: git://github.com/floehopper/mocha.git
|
||||
revision: d1715ff
|
||||
revision: e0a00a7
|
||||
specs:
|
||||
mocha (0.9.8.20090918115329)
|
||||
mocha (0.9.8.20100819090654)
|
||||
rake
|
||||
|
||||
GIT
|
||||
@ -13,14 +13,14 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/locomotivecms/liquid.git
|
||||
revision: a41213c
|
||||
ref: a41213c77cbc81dab87d
|
||||
revision: dbcc0b1
|
||||
ref: dbcc0b1d9c189b3e3a13
|
||||
specs:
|
||||
liquid (2.1.3)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/plataformatec/devise.git
|
||||
revision: 01c272c
|
||||
revision: 219c05c
|
||||
specs:
|
||||
devise (1.2.0)
|
||||
bcrypt-ruby (~> 2.1.2)
|
||||
@ -96,13 +96,13 @@ GEM
|
||||
term-ansicolor (~> 1.0.4)
|
||||
cucumber-rails (0.3.2)
|
||||
cucumber (>= 0.8.0)
|
||||
culerity (0.2.10)
|
||||
culerity (0.2.12)
|
||||
daemons (1.1.0)
|
||||
database_cleaner (0.5.2)
|
||||
diff-lcs (1.1.2)
|
||||
erubis (2.6.6)
|
||||
abstract (>= 1.0.0)
|
||||
factory_girl (1.3.1)
|
||||
factory_girl (1.3.2)
|
||||
factory_girl_rails (1.0)
|
||||
factory_girl (~> 1.3)
|
||||
rails (>= 3.0.0.beta4)
|
||||
@ -135,7 +135,7 @@ GEM
|
||||
gemcutter (>= 0.1.0)
|
||||
git (>= 1.2.5)
|
||||
rubyforge (>= 2.0.0)
|
||||
json_pure (1.4.3)
|
||||
json_pure (1.4.6)
|
||||
launchy (0.3.7)
|
||||
configuration (>= 0.0.5)
|
||||
rake (>= 0.8.1)
|
||||
@ -170,7 +170,7 @@ GEM
|
||||
pickle (>= 0.3.0)
|
||||
polyglot (0.3.1)
|
||||
rack (1.2.1)
|
||||
rack-mount (0.6.9)
|
||||
rack-mount (0.6.12)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (0.5.4)
|
||||
rack (>= 1.0)
|
||||
@ -211,7 +211,7 @@ GEM
|
||||
rubyforge (2.0.4)
|
||||
json_pure (>= 1.1.7)
|
||||
rubyzip (0.9.4)
|
||||
selenium-webdriver (0.0.27)
|
||||
selenium-webdriver (0.0.28)
|
||||
ffi (>= 0.6.1)
|
||||
json_pure
|
||||
rubyzip
|
||||
|
25
app/models/editable_element.rb
Normal file
25
app/models/editable_element.rb
Normal file
@ -0,0 +1,25 @@
|
||||
class EditableElement
|
||||
|
||||
include Mongoid::Document
|
||||
|
||||
## fields ##
|
||||
field :slug
|
||||
field :block
|
||||
field :content
|
||||
field :default_content
|
||||
field :hint
|
||||
field :disabled, :type => Boolean, :default => false
|
||||
|
||||
## associations ##
|
||||
embedded_in :page, :inverse_of => :editable_elements
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :slug
|
||||
|
||||
## methods ##
|
||||
|
||||
def content
|
||||
self.read_attribute(:content).blank? ? self.default_content : self.read_attribute(:content)
|
||||
end
|
||||
|
||||
end
|
51
app/models/extensions/page/editable_elements.rb
Normal file
51
app/models/extensions/page/editable_elements.rb
Normal file
@ -0,0 +1,51 @@
|
||||
module Models
|
||||
module Extensions
|
||||
module Page
|
||||
module EditableElements
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
embeds_many :editable_elements
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def find_editable_element(block, slug)
|
||||
self.editable_elements.detect { |el| el.block == block && el.slug == slug }
|
||||
end
|
||||
|
||||
def add_or_update_editable_element(attributes)
|
||||
element = self.find_editable_element(attributes[:block], attributes[:slug])
|
||||
|
||||
if element
|
||||
element.attributes = attributes
|
||||
else
|
||||
self.editable_elements.build(attributes)
|
||||
end
|
||||
end
|
||||
|
||||
def disable_all_editable_elements
|
||||
self.editable_elements.each { |el| el.disabled = true }
|
||||
end
|
||||
|
||||
def enable_editable_elements(block)
|
||||
self.editable_elements.each { |el| el.disabled = false if el.block == block }
|
||||
end
|
||||
|
||||
def merge_editable_elements_from_page(source)
|
||||
source.editable_elements.each do |el|
|
||||
existing_el = self.find_editable_element(el.block, el.slug)
|
||||
|
||||
if existing_el.nil? # new one from parents
|
||||
self.editable_elements.build(el.attributes.merge(:disabled => true))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -31,6 +31,7 @@ module Models
|
||||
@template_changed = true
|
||||
|
||||
@parsing_errors = []
|
||||
|
||||
begin
|
||||
self._parse_and_serialize_template
|
||||
rescue ::Liquid::SyntaxError => error
|
||||
@ -51,35 +52,42 @@ module Models
|
||||
end
|
||||
|
||||
def parse(context = {})
|
||||
@template = ::Liquid::Template.parse(self.raw_template, { :site => self.site, :page => self }.merge(context))
|
||||
self.disable_all_editable_elements
|
||||
|
||||
default_context = { :site => self.site, :page => self, :templates => [], :snippets => [] }
|
||||
|
||||
@template = ::Liquid::Template.parse(self.raw_template, default_context.merge(context))
|
||||
self.template_dependencies = context[:templates]
|
||||
self.snippet_dependencies = context[:snippets]
|
||||
|
||||
@template.root.context.clear
|
||||
|
||||
dependencies = all_dependencies(@template.root, { :templates => [], :snippets => [] })
|
||||
|
||||
self.template_dependencies = dependencies[:templates]
|
||||
self.snippet_dependencies = dependencies[:snippets]
|
||||
#
|
||||
# dependencies = all_dependencies(@template.root, { :templates => [], :snippets => [] })
|
||||
#
|
||||
# self.template_dependencies = dependencies[:templates]
|
||||
# self.snippet_dependencies = dependencies[:snippets]
|
||||
end
|
||||
|
||||
def template_must_be_valid
|
||||
@parsing_errors.try(:each) { |msg| self.errors.add :template, msg }
|
||||
end
|
||||
|
||||
def all_dependencies(node, dependencies = {})
|
||||
case node
|
||||
when Locomotive::Liquid::Tags::Extends
|
||||
dependencies[:templates] << node.page_id
|
||||
when Locomotive::Liquid::Tags::Snippet
|
||||
dependencies[:snippets] << node.slug
|
||||
end
|
||||
|
||||
if node.respond_to?(:nodelist) && node.nodelist
|
||||
node.nodelist.each do |child|
|
||||
self.all_dependencies(child, dependencies)
|
||||
end
|
||||
end
|
||||
|
||||
dependencies
|
||||
end
|
||||
# def all_dependencies(node, dependencies = {})
|
||||
# case node
|
||||
# when Locomotive::Liquid::Tags::Extends
|
||||
# dependencies[:templates] << node.page_id
|
||||
# when Locomotive::Liquid::Tags::Snippet
|
||||
# dependencies[:snippets] << node.slug
|
||||
# end
|
||||
#
|
||||
# if node.respond_to?(:nodelist) && node.nodelist
|
||||
# node.nodelist.each do |child|
|
||||
# self.all_dependencies(child, dependencies)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# dependencies
|
||||
# end
|
||||
|
||||
def update_template_descendants
|
||||
return unless @template_changed == true
|
||||
|
@ -4,7 +4,7 @@ class Page
|
||||
|
||||
## Extensions ##
|
||||
include Models::Extensions::Page::Tree
|
||||
# include Models::Extensions::Page::Parts
|
||||
include Models::Extensions::Page::EditableElements
|
||||
include Models::Extensions::Page::Parse
|
||||
include Models::Extensions::Page::Render
|
||||
include Models::Extensions::Page::Templatized
|
||||
|
@ -41,8 +41,11 @@ class Snippet
|
||||
end
|
||||
|
||||
def _change_snippet_inside_template(node)
|
||||
if node.is_a?(Locomotive::Liquid::Tags::Snippet)
|
||||
node.refresh(self)
|
||||
case node
|
||||
when Locomotive::Liquid::Tags::Snippet
|
||||
node.refresh(self) if node.slug == self.slug
|
||||
when Locomotive::Liquid::Tags::Block
|
||||
self._change_snippet_inside_template(node.parent) if node.parent
|
||||
else
|
||||
if node.respond_to?(:nodelist)
|
||||
node.nodelist.each do |child|
|
||||
|
55
features/engine/editable_elements.feature
Normal file
55
features/engine/editable_elements.feature
Normal file
@ -0,0 +1,55 @@
|
||||
Feature: Editable elements
|
||||
As a designer
|
||||
I want to define content which will be edited by the website editor
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
|
||||
Scenario: Simple short text element
|
||||
Given a page named "hello-world" with the template:
|
||||
"""
|
||||
My application says {% editable_short_text 'a_sentence', hint: 'please enter a new sentence' %}Hello world{% endeditable_short_text %}
|
||||
"""
|
||||
When I view the rendered page at "/hello-world"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
My application says Hello world
|
||||
"""
|
||||
|
||||
Scenario: Modified short text element
|
||||
Given a page named "hello-world" with the template:
|
||||
"""
|
||||
My application says {% editable_short_text 'a_sentence', hint: 'please enter a new sentence' %}Hello world{% endeditable_short_text %}
|
||||
"""
|
||||
And the editable element "a_sentence" with the content "Bonjour" in the "hello-world" page
|
||||
When I view the rendered page at "/hello-world"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
My application says Bonjour
|
||||
"""
|
||||
|
||||
Scenario: Short text element inside a block
|
||||
Given a page named "hello-world" with the template:
|
||||
"""
|
||||
{% block main %}My application says {% editable_short_text 'a_sentence' %}Hello world{% endeditable_short_text %}{% endblock %}
|
||||
"""
|
||||
When I view the rendered page at "/hello-world"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
My application says Hello world
|
||||
"""
|
||||
|
||||
Scenario: Not modified short text element inside a block and with page inheritance
|
||||
Given a page named "hello-world" with the template:
|
||||
"""
|
||||
{% block main %}My application says {% editable_short_text 'a_sentence' %}Hello world{% endeditable_short_text %}{% endblock %}
|
||||
"""
|
||||
Given a page named "another-hello-world" with the template:
|
||||
"""
|
||||
{% extends hello-world %}
|
||||
"""
|
||||
When I view the rendered page at "/another-hello-world"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
My application says Hello world
|
||||
"""
|
10
features/step_definitions/editable_elements_steps.rb
Normal file
10
features/step_definitions/editable_elements_steps.rb
Normal file
@ -0,0 +1,10 @@
|
||||
Given /^a simple page named "([^"]*)" with the body:$/ do |page_slug, page_contents|
|
||||
@page = create_content_page(page_slug, page_contents)
|
||||
end
|
||||
|
||||
# modify an editable element
|
||||
Given /^the editable element "([^"]*)" with the content "([^"]*)" in the "([^"]*)" page$/ do |slug, content, page_slug|
|
||||
page = @site.pages.where(:slug => page_slug).first
|
||||
page.find_editable_element(nil, slug).content = content
|
||||
page.save!
|
||||
end
|
48
lib/locomotive/liquid/tags/editable_short_text.rb
Normal file
48
lib/locomotive/liquid/tags/editable_short_text.rb
Normal file
@ -0,0 +1,48 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
module Tags
|
||||
class EditableShortText < ::Liquid::Block
|
||||
|
||||
Syntax = /(#{::Liquid::QuotedFragment})(\s*,\s*#{::Liquid::Expression}+)?/
|
||||
|
||||
def initialize(tag_name, markup, tokens, context)
|
||||
if markup =~ Syntax
|
||||
@slug = $1.gsub('\'', '')
|
||||
@options = {}
|
||||
markup.scan(::Liquid::TagAttributes) { |key, value| @options[key.to_sym] = value.gsub(/^'/, '').gsub(/'$/, '') }
|
||||
else
|
||||
raise ::Liquid::SyntaxError.new("Syntax Error in 'editable_short_text' - Valid syntax: editable_short_text <slug>(, <options>)")
|
||||
end
|
||||
|
||||
super
|
||||
|
||||
puts "@nodelist = #{@nodelist.inspect}"
|
||||
|
||||
@context[:page].add_or_update_editable_element({
|
||||
:block => @context[:current_block].try(:name),
|
||||
:slug => @slug,
|
||||
:hint => @options[:hint],
|
||||
:default_content => @nodelist.first.to_s,
|
||||
:disabled => false
|
||||
})
|
||||
end
|
||||
|
||||
def render(context)
|
||||
current_page = context.registers[:page]
|
||||
puts "[EditableShortText] rendering #{context['block'].inspect} / #{current_page.editable_elements.inspect}"
|
||||
|
||||
element = current_page.find_editable_element(context['block'].try(:name), @slug)
|
||||
|
||||
if element
|
||||
element.content
|
||||
else
|
||||
Locomotive.logger "[editable short text] missing editable short text #{context[:block].name} / #{@slug}"
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('editable_short_text', EditableShortText)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -3,26 +3,27 @@ module Locomotive
|
||||
module Tags
|
||||
class Extends < ::Liquid::Extends
|
||||
|
||||
attr_accessor :page_id
|
||||
attr_accessor :page_id # parent page id
|
||||
|
||||
def parse_parent_template(context)
|
||||
page = nil
|
||||
|
||||
if @template_name == 'parent'
|
||||
if context[:cached_parent]
|
||||
page = context[:cached_parent]
|
||||
context[:cached_parent] = nil
|
||||
else
|
||||
page = context[:page].parent
|
||||
end
|
||||
def initialize(tag_name, markup, tokens, context)
|
||||
if markup =~ Syntax
|
||||
@template_name = $1
|
||||
else
|
||||
path = @template_name.gsub("'", '')
|
||||
page = context[:cached_pages].try(:[], path) || context[:site].pages.where(:fullpath => path).first
|
||||
raise SyntaxError.new("Error in tag 'extends' - Valid syntax: extends [template]")
|
||||
end
|
||||
|
||||
raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if page.nil?
|
||||
retrieve_parent_page
|
||||
|
||||
@page_id = page.id
|
||||
# before parsing the embedded tokens, get editable elements from parent page
|
||||
@context[:page].merge_editable_elements_from_page(@context[:parent_page])
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_parent_template
|
||||
page = @context[:parent_page]
|
||||
|
||||
template = page.template
|
||||
|
||||
@ -30,13 +31,35 @@ module Locomotive
|
||||
blocks = find_blocks(template.root.nodelist)
|
||||
|
||||
blocks.each_value do |block|
|
||||
block.send(:instance_variable_set, :"@context", context)
|
||||
block.send(:instance_variable_set, :"@context", @context)
|
||||
block.end_tag
|
||||
end
|
||||
|
||||
@context[:snippets] = page.snippet_dependencies
|
||||
@context[:templates] = [*page.template_dependencies] + [@page_id]
|
||||
|
||||
template
|
||||
end
|
||||
|
||||
def retrieve_parent_page
|
||||
if @template_name == 'parent'
|
||||
if @context[:cached_parent]
|
||||
@context[:parent] = @context[:cached_parent]
|
||||
@context[:cached_parent] = nil
|
||||
else
|
||||
@context[:parent_page] = @context[:page].parent
|
||||
end
|
||||
else
|
||||
path = @template_name.gsub("'", '')
|
||||
@context[:parent_page] = @context[:cached_pages].try(:[], path) ||
|
||||
@context[:site].pages.where(:fullpath => path).first
|
||||
end
|
||||
|
||||
raise PageNotFound.new("Page with fullpath '#{@template_name}' was not found") if @context[:parent_page].nil?
|
||||
|
||||
@page_id = @context[:parent_page].id
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('extends', Extends)
|
||||
|
31
lib/locomotive/liquid/tags/inherited_block.rb
Normal file
31
lib/locomotive/liquid/tags/inherited_block.rb
Normal file
@ -0,0 +1,31 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
module Tags
|
||||
class InheritedBlock < ::Liquid::InheritedBlock
|
||||
|
||||
def end_tag
|
||||
super
|
||||
|
||||
if self.contains_super?(@nodelist) # then enable all editable_elements (coming from the parent block too)
|
||||
@context[:page].enable_editable_elements(@name)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def contains_super?(nodelist)
|
||||
nodelist.any? do |node|
|
||||
if node.is_a?(String) && node =~ /\{\{\s*block.super\s*\}\}/
|
||||
true
|
||||
elsif node.respond_to?(:nodelist) && !node.is_a?(Locomotive::Liquid::Tags::InheritedBlock)
|
||||
contains_super?(node.nodelist)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('block', InheritedBlock)
|
||||
end
|
||||
end
|
||||
end
|
@ -12,6 +12,8 @@ module Locomotive
|
||||
|
||||
@slug = @template_name.gsub('\'', '')
|
||||
|
||||
context[:snippets] << @slug
|
||||
|
||||
snippet = context[:site].snippets.where(:slug => @slug).first
|
||||
|
||||
self.refresh(snippet, context) if snippet
|
||||
|
20
spec/lib/locomotive/liquid/tags/editable_short_text_spec.rb
Normal file
20
spec/lib/locomotive/liquid/tags/editable_short_text_spec.rb
Normal file
@ -0,0 +1,20 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Tags::EditableShortText do
|
||||
|
||||
it 'should have a valid syntax' do
|
||||
markup = "'title', hint: 'Simple short text'"
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::EditableShortText.new('editable_short_text', markup, ["{% endeditable_short_text %}"], {})
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
# it 'should raise an error if the syntax is incorrect' do
|
||||
# ["contents.projects by a", "contents.projects", "contents.projects 5"].each do |markup|
|
||||
# lambda do
|
||||
# Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"], {})
|
||||
# end.should raise_error
|
||||
# end
|
||||
# end
|
||||
|
||||
end
|
Loading…
Reference in New Issue
Block a user