fix the editable_elements method of the page liquid drop (work-around for locomotivecms/engine#968)

did committed Nov 25, 2015
commit 9ae8fa4283e3e57dad7c3e4abb4ea25d4cc91df3
Showing 11 changed files with 143 additions and 24 deletions
locomotive/steam/liquid/drops/page.rb b/lib/locomotive/steam/liquid/drops/page.rb +36 -16
@@ @@ -62,32 +62,52 @@ module Locomotive
end
def build_editable_elements_hash
- {}.tap do |hash|
- repository.editable_elements_of(@_source).each do |el|
- safe_slug = el.slug.parameterize.underscore
- keys = el.block.try(:split, '/').try(:compact) || []
+ {}.tap do |hash|
+ # default content from the template itself
+ _build_default_editable_elements_hash(hash)
- _hash = _build_editable_elements_hashes(hash, keys)
+ # content updated by the users
+ _build_editable_elements_hash(hash)
+ end
+ end
- _hash[safe_slug] = el.content
- end
- end
+ def _build_default_editable_elements_hash(hash)
+ (@context.registers[:default_editable_content] || []).each do |key, content|
+ keys = key.split('/')
+ _build_editable_elements_hashes(hash, keys, keys.pop, content)
end
+ end
- def _build_editable_elements_hashes(hash, keys)
- _hash = hash
+ def _build_editable_elements_hash(hash)
+ (repository.editable_elements_of(@_source) || []).each do |el|
+ keys = el.block.try(:split, '/').try(:compact) || []
- keys.each do |key|
- safe_key = key.parameterize.underscore
+ # decorate the el instance which is localized because
+ # el.content returns a I18nField.
+ content = editable_element_content(el)
- _hash[safe_key] = {} if _hash[safe_key].nil?
+ _build_editable_elements_hashes(hash, keys, el.slug, content)
+ end
+ end
- _hash = _hash[safe_key]
- end
+ def editable_element_content(element)
+ Locomotive::Steam::Decorators::I18nDecorator.new(element,
+ @_source.__locale__,
+ @_source.__default_locale__).content
+ end
+
+ def _build_editable_elements_hashes(hash, keys, slug, content)
+ last_hash = hash
- _hash
+ # go the last hash
+ keys.each do |key|
+ safe_key = key.parameterize.underscore
+ last_hash = (last_hash[safe_key] ||= {})
end
+ last_hash[slug.parameterize.underscore] = content
+ end
+
end
end
end
locomotive/steam/liquid/tags/editable/base.rb b/lib/locomotive/steam/liquid/tags/editable/base.rb +11 -0
@@ @@ -25,6 +25,8 @@ module Locomotive
def parse(tokens)
super.tap do
ActiveSupport::Notifications.instrument("steam.parse.editable.#{@tag_name}", page: options[:page], attributes: default_element_attributes)
+
+ register_default_content
end
end
@@ @@ -56,6 +58,15 @@ module Locomotive
pages[@page_fullpath] ||= service.find(@page_fullpath)
end
+ def register_default_content
+ return if options[:default_editable_content].nil?
+
+ hash = options[:default_editable_content]
+ key = [current_inherited_block_name, @slug].compact.join('/')
+
+ hash[key] = render_default_content
+ end
+
def default_element_attributes
{
block: self.current_inherited_block_name,
locomotive/steam/liquid/tags/editable/model.rb b/lib/locomotive/steam/liquid/tags/editable/model.rb +4 -0
@@ @@ -9,6 +9,10 @@ module Locomotive
default_render(context)
end
+ def render_default_content
+ nil
+ end
+
end
::Liquid::Template.register_tag('editable_model'.freeze, Model)
locomotive/steam/liquid/template.rb b/lib/locomotive/steam/liquid/template.rb +33 -0
@@ @@ -0,0 +1,33 @@
+ module Locomotive
+ module Steam
+ module Liquid
+
+ class Template < ::Liquid::Template
+
+ # When we render a Locomotive template, we need to know what are
+ # the default content of all the editable elements.
+ # Without this, developers are unable to use statements like
+ # the following: {{ page.editable_elements.content.header.title }}
+ def render(*args)
+ if args.first && args.first.is_a?(::Liquid::Context)
+ content = @options[:default_editable_content]
+ args.first.registers[:default_editable_content] = content
+ end
+
+ super
+ end
+
+ class << self
+
+ def parse(source, options = {})
+ template = new
+ template.parse(source, options)
+ end
+
+ end
+
+ end
+
+ end
+ end
+ end
locomotive/steam/models/repository.rb b/lib/locomotive/steam/models/repository.rb +1 -0
@@ @@ -11,6 +11,7 @@ module Locomotive::Steam
attr_accessor :adapter, :scope, :local_conditions
def_delegators :@scope, :site, :site=, :locale, :locale=
+ def_delegators :all, :each
def initialize(adapter, site = nil, locale = nil)
@adapter = adapter
locomotive/steam/repositories/page_repository.rb b/lib/locomotive/steam/repositories/page_repository.rb +1 -1
@@ @@ -81,7 +81,7 @@ module Locomotive
end
def editable_element_for(page, block, slug)
- return nil if page.nil?
+ return nil if page.nil? || page.editable_elements.nil?
page.editable_elements.first do
where(block: block, slug: slug)
end
locomotive/steam/services/liquid_parser_service.rb b/lib/locomotive/steam/services/liquid_parser_service.rb +6 -5
@@ @@ -7,15 +7,16 @@ module Locomotive
def parse(page)
_parse(page,
- page: page,
- parent_finder: parent_finder,
- snippet_finder: snippet_finder,
- parser: self)
+ page: page,
+ parent_finder: parent_finder,
+ snippet_finder: snippet_finder,
+ parser: self,
+ default_editable_content: {})
end
def _parse(object, options = {})
# Note: the template must not be parsed here
- ::Liquid::Template.parse(object.liquid_source, options)
+ Locomotive::Steam::Liquid::Template.parse(object.liquid_source, options)
end
end
spec/integration/liquid/drops/page_spec.rb +43 -0
@@ @@ -0,0 +1,43 @@
+ require 'spec_helper'
+
+ describe Locomotive::Steam::Liquid::Drops::Page do
+
+ describe '#editable_elements' do
+
+ let(:source) { <<-EOF
+ <h1>{{ page.editable_elements.content.header.title }}</h1>
+ {% block content %}
+ {% block header %}
+ {% editable_text title %}Hello world{% endeditable_text %}
+ {% endblock %}
+ {% endblock %}
+ EOF
+ }
+
+ let(:elements) { nil }
+ let(:page) { instance_double('Page', localized_attributes: [], fullpath: 'index', editable_elements: elements) }
+ let(:drop) { described_class.new(page) }
+ let(:services) { Locomotive::Steam::Services.build_instance }
+ let(:context) { ::Liquid::Context.new({ 'page' => drop }, {}, { page: page, services: services }, true) }
+
+ subject { render_template(source, context, { page: page, default_editable_content: {} }) }
+
+ it { is_expected.to match /<h1>Hello world<\/h1>/ }
+
+ context 'content updated by an user' do
+
+ let(:elements) { [instance_double('EditableText', block: 'content/header', slug: 'title', content: 'Bonjour le monde', :base_url= => nil, localized_attributes: [], default_content?: false, format: 'raw')] }
+
+ before do
+ services.locale = :en
+ services.repositories.current_site = instance_double('Site', default_locale: :en)
+ allow(services.repositories.page).to receive(:editable_elements_of).and_return(elements)
+ end
+
+ it { is_expected.to match /<h1>Bonjour le monde<\/h1>/ }
+
+ end
+
+ end
+
+ end
spec/support/liquid.rb +1 -1
@@ @@ -1,7 +1,7 @@
def render_template(source, context = nil, options = {})
context ||= ::Liquid::Context.new
context.exception_handler = ->(e) { true }
- ::Liquid::Template.parse(source, options).render(context)
+ Locomotive::Steam::Liquid::Template.parse(source, options).render(context)
end
def parse_template(source, options = nil)
spec/unit/liquid/drops/page_spec.rb +1 -1
@@ @@ -70,7 +70,7 @@ describe Locomotive::Steam::Liquid::Drops::Page do
describe '#editable_elements' do
- let(:elements) { [instance_double('EditableElement', block: 'top/left', slug: 'banner', content: 'Hello world')] }
+ let(:elements) { [instance_double('EditableElement', block: 'top/left', slug: 'banner', content: 'Hello world', localized_attributes: [])] }
before do
allow(services.repositories.page).to receive(:editable_elements_of).with(page).and_return(elements)
spec/unit/repositories/page_repository_spec.rb +6 -0
@@ @@ -331,6 +331,12 @@ describe Locomotive::Steam::PageRepository do
end
+ context 'looping over' do
+
+ it { i = 0; subject.each { |el| i += 1 }; expect(i).to eq 1 }
+
+ end
+
end
end