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 | |