templatized page can now use models from the main app + add new liquid filters
This commit is contained in:
parent
39d9c354da
commit
62eaeb10f5
@ -27,7 +27,7 @@ PATH
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
cells (~> 3.8.0)
|
||||
codemirror-rails (~> 2.21)
|
||||
custom_fields (~> 2.0.0.rc3)
|
||||
custom_fields (~> 2.0.0.rc4)
|
||||
devise (~> 1.5.3)
|
||||
dragonfly (~> 0.9.8)
|
||||
flash_cookie_session (~> 1.1.1)
|
||||
@ -56,7 +56,7 @@ PATH
|
||||
PATH
|
||||
remote: ../gems/custom_fields
|
||||
specs:
|
||||
custom_fields (2.0.0.rc3)
|
||||
custom_fields (2.0.0.rc4)
|
||||
activesupport (~> 3.2.1)
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
mongoid (~> 2.4.3)
|
||||
@ -123,7 +123,7 @@ GEM
|
||||
childprocess (0.3.0)
|
||||
ffi (~> 1.0.6)
|
||||
chunky_png (1.2.5)
|
||||
codemirror-rails (2.21)
|
||||
codemirror-rails (2.21.1)
|
||||
railties (~> 3.0)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
|
@ -21,4 +21,7 @@ class Locomotive.Models.Page extends Backbone.Model
|
||||
delete hash['editable_elements']
|
||||
hash.editable_elements = @get('editable_elements').toJSONForSave() if @get('editable_elements')? && @get('editable_elements').length > 0
|
||||
|
||||
delete hash['target_klass_name']
|
||||
hash.target_klass_name = @get('target_klass_name') if @get('templatized') == true
|
||||
|
||||
class Locomotive.Models.PagesCollection extends Backbone.Collection
|
@ -111,9 +111,9 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
|
||||
@_enable_checkbox 'templatized',
|
||||
features: ['slug', 'redirect', 'listed']
|
||||
on_callback: =>
|
||||
@$('li#page_content_type_id_input').show()
|
||||
@$('li#page_target_klass_name_input').show()
|
||||
off_callback: =>
|
||||
@$('li#page_content_type_id_input').hide()
|
||||
@$('li#page_target_klass_name_input').hide()
|
||||
|
||||
enable_redirect_checkbox: ->
|
||||
@_enable_checkbox 'redirect',
|
||||
|
@ -15,22 +15,12 @@ module Locomotive
|
||||
|
||||
skip_before_filter :verify_authenticity_token
|
||||
|
||||
skip_load_and_authorize_resource
|
||||
|
||||
self.responder = Locomotive::ActionController::Responder # custom responder
|
||||
|
||||
respond_to :json, :xml
|
||||
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
::Locomotive.log "[CanCan::AccessDenied] #{exception.inspect}"
|
||||
|
||||
if request.xhr?
|
||||
render :json => { :error => exception.message }
|
||||
else
|
||||
flash[:alert] = exception.message
|
||||
|
||||
redirect_to pages_url
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def current_ability
|
||||
|
@ -32,6 +32,13 @@ module Locomotive
|
||||
list
|
||||
end
|
||||
|
||||
def options_for_target_klass_name
|
||||
base_models = current_site.content_types.map do |type|
|
||||
[type.name.humanize, type.klass_with_custom_fields(:entries)]
|
||||
end
|
||||
base_models + Locomotive.config.models_for_templatization.map { |name| [name.underscore.humanize, name] }
|
||||
end
|
||||
|
||||
def options_for_page_cache_strategy
|
||||
[
|
||||
[t('.cache_strategy.none'), 'none'],
|
||||
|
@ -57,6 +57,10 @@ module Locomotive
|
||||
next_or_previous :lt
|
||||
end
|
||||
|
||||
def self.find_by_permalink(permalink)
|
||||
self.where(:_slug => permalink).first
|
||||
end
|
||||
|
||||
def self.sort_entries!(ids)
|
||||
list = self.any_in(:_id => ids.map { |id| BSON::ObjectId.from_string(id.to_s) }).to_a
|
||||
ids.each_with_index do |id, position|
|
||||
|
@ -18,103 +18,99 @@ module Locomotive
|
||||
accepts_nested_attributes_for :editable_elements
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def disable_parent_editable_elements(block)
|
||||
self.editable_elements.each { |el| el.disabled = true if el.from_parent? && el.block == block }
|
||||
end
|
||||
|
||||
def disable_parent_editable_elements(block)
|
||||
self.editable_elements.each { |el| el.disabled = true if el.from_parent? && el.block == block }
|
||||
def disable_all_editable_elements
|
||||
self.editable_elements.each { |el| el.disabled = true }
|
||||
end
|
||||
|
||||
def editable_element_blocks
|
||||
self.editable_elements.collect(&:block)
|
||||
end
|
||||
|
||||
def enabled_editable_elements
|
||||
self.editable_elements.by_priority.reject { |el| el.disabled? }
|
||||
end
|
||||
|
||||
def editable_elements_grouped_by_blocks
|
||||
groups = self.enabled_editable_elements.group_by(&:block)
|
||||
groups.delete_if { |block, elements| elements.empty? }
|
||||
end
|
||||
|
||||
def find_editable_element(block, slug)
|
||||
self.editable_elements.detect { |el| el.block == block && el.slug == slug }
|
||||
end
|
||||
|
||||
def find_editable_files
|
||||
self.editable_elements.find_all { |el| el.respond_to?(:source) }
|
||||
end
|
||||
|
||||
def add_or_update_editable_element(attributes, type)
|
||||
element = self.find_editable_element(attributes[:block], attributes[:slug])
|
||||
|
||||
if element
|
||||
element.attributes = attributes
|
||||
else
|
||||
self.editable_elements.build(attributes, type)
|
||||
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 editable_element_blocks
|
||||
self.editable_elements.collect(&:block)
|
||||
end
|
||||
def merge_editable_elements_from_page(source)
|
||||
source.editable_elements.each do |el|
|
||||
next if el.disabled? or !el.assignable?
|
||||
|
||||
def enabled_editable_elements
|
||||
self.editable_elements.by_priority.reject { |el| el.disabled? }
|
||||
end
|
||||
existing_el = self.find_editable_element(el.block, el.slug)
|
||||
|
||||
def editable_elements_grouped_by_blocks
|
||||
groups = self.enabled_editable_elements.group_by(&:block)
|
||||
groups.delete_if { |block, elements| elements.empty? }
|
||||
end
|
||||
if existing_el.nil? # new one from parents
|
||||
new_attributes = el.attributes.merge(:from_parent => true)
|
||||
|
||||
def find_editable_element(block, slug)
|
||||
self.editable_elements.detect { |el| el.block == block && el.slug == slug }
|
||||
end
|
||||
|
||||
def find_editable_files
|
||||
self.editable_elements.find_all { |el| el.respond_to?(:source) }
|
||||
end
|
||||
|
||||
def add_or_update_editable_element(attributes, type)
|
||||
element = self.find_editable_element(attributes[:block], attributes[:slug])
|
||||
|
||||
if element
|
||||
element.attributes = attributes
|
||||
else
|
||||
self.editable_elements.build(attributes, type)
|
||||
end
|
||||
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|
|
||||
next if el.disabled? or !el.assignable?
|
||||
|
||||
existing_el = self.find_editable_element(el.block, el.slug)
|
||||
|
||||
if existing_el.nil? # new one from parents
|
||||
new_attributes = el.attributes.merge(:from_parent => true)
|
||||
|
||||
if new_attributes['default_attribute'].present?
|
||||
new_attributes['default_content'] = self.send(new_attributes['default_attribute']) || el.content
|
||||
else
|
||||
if el.respond_to?(:content) # only for text
|
||||
new_attributes['default_content'] = el.content
|
||||
end
|
||||
end
|
||||
|
||||
self.editable_elements.build(new_attributes, el.class)
|
||||
elsif existing_el.default_attribute.nil?
|
||||
existing_el.attributes = { :disabled => false, :default_content => el.content }
|
||||
if new_attributes['default_attribute'].present?
|
||||
new_attributes['default_content'] = self.send(new_attributes['default_attribute']) || el.content
|
||||
else
|
||||
existing_el.attributes = { :disabled => false }
|
||||
if el.respond_to?(:content) # only for text
|
||||
new_attributes['default_content'] = el.content
|
||||
end
|
||||
end
|
||||
|
||||
self.editable_elements.build(new_attributes, el.class)
|
||||
elsif existing_el.default_attribute.nil?
|
||||
existing_el.attributes = { :disabled => false, :default_content => el.content }
|
||||
else
|
||||
existing_el.attributes = { :disabled => false }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_disabled_editable_elements
|
||||
return unless self.editable_elements.any? { |el| el.disabled? }
|
||||
def remove_disabled_editable_elements
|
||||
return unless self.editable_elements.any? { |el| el.disabled? }
|
||||
|
||||
# super fast way to remove useless elements all in once (TODO callbacks)
|
||||
self.collection.update(self.atomic_selector, '$pull' => { 'editable_elements' => { 'disabled' => true } })
|
||||
end
|
||||
# super fast way to remove useless elements all in once (TODO callbacks)
|
||||
self.collection.update(self.atomic_selector, '$pull' => { 'editable_elements' => { 'disabled' => true } })
|
||||
end
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
## callbacks for editable files
|
||||
## callbacks for editable files
|
||||
|
||||
# equivalent to "after_save :store_source!" in EditableFile
|
||||
def store_file_sources!
|
||||
self.find_editable_files.collect(&:store_source!)
|
||||
end
|
||||
# equivalent to "after_save :store_source!" in EditableFile
|
||||
def store_file_sources!
|
||||
self.find_editable_files.collect(&:store_source!)
|
||||
end
|
||||
|
||||
# equivalent to "before_save :write_source_identifier" in EditableFile
|
||||
def write_file_source_identifiers
|
||||
self.find_editable_files.collect(&:write_source_identifier)
|
||||
end
|
||||
|
||||
# equivalent to "after_destroy :remove_source!" in EditableFile
|
||||
def remove_file_sources!
|
||||
self.find_editable_files.collect(&:remove_source!)
|
||||
end
|
||||
# equivalent to "before_save :write_source_identifier" in EditableFile
|
||||
def write_file_source_identifiers
|
||||
self.find_editable_files.collect(&:write_source_identifier)
|
||||
end
|
||||
|
||||
# equivalent to "after_destroy :remove_source!" in EditableFile
|
||||
def remove_file_sources!
|
||||
self.find_editable_files.collect(&:remove_source!)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -20,94 +20,90 @@ module Locomotive
|
||||
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def template
|
||||
@template ||= Marshal.load(self.serialized_template.to_s) rescue nil
|
||||
end
|
||||
|
||||
def template
|
||||
@template ||= Marshal.load(self.serialized_template.to_s) rescue nil
|
||||
end
|
||||
protected
|
||||
|
||||
protected
|
||||
def serialize_template
|
||||
if self.new_record? || self.raw_template_changed?
|
||||
@template_changed = true
|
||||
|
||||
def serialize_template
|
||||
if self.new_record? || self.raw_template_changed?
|
||||
@template_changed = true
|
||||
@parsing_errors = []
|
||||
|
||||
@parsing_errors = []
|
||||
|
||||
begin
|
||||
self._parse_and_serialize_template
|
||||
rescue ::Liquid::SyntaxError => error
|
||||
@parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s, :scope => [:errors, :messages, :page])
|
||||
rescue ::Locomotive::Liquid::PageNotFound => error
|
||||
@parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath, :scope => [:errors, :messages, :page])
|
||||
end
|
||||
begin
|
||||
self._parse_and_serialize_template
|
||||
rescue ::Liquid::SyntaxError => error
|
||||
@parsing_errors << I18n.t(:liquid_syntax, :fullpath => self.fullpath, :error => error.to_s, :scope => [:errors, :messages, :page])
|
||||
rescue ::Locomotive::Liquid::PageNotFound => error
|
||||
@parsing_errors << I18n.t(:liquid_extend, :fullpath => self.fullpath, :scope => [:errors, :messages, :page])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def _parse_and_serialize_template(context = {})
|
||||
self.parse(context)
|
||||
self._serialize_template
|
||||
def _parse_and_serialize_template(context = {})
|
||||
self.parse(context)
|
||||
self._serialize_template
|
||||
end
|
||||
|
||||
def _serialize_template
|
||||
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
||||
end
|
||||
|
||||
def parse(context = {})
|
||||
self.disable_all_editable_elements
|
||||
|
||||
default_context = { :site => self.site, :page => self, :templates => [], :snippets => [] }
|
||||
|
||||
context = default_context.merge(context)
|
||||
|
||||
@template = ::Liquid::Template.parse(self.raw_template, context)
|
||||
|
||||
self.template_dependencies = context[:templates]
|
||||
self.snippet_dependencies = context[:snippets]
|
||||
|
||||
@template.root.context.clear
|
||||
end
|
||||
|
||||
def template_must_be_valid
|
||||
@parsing_errors.try(:each) do |msg|
|
||||
self.errors.add :template, msg
|
||||
self.errors.add :raw_template, msg
|
||||
end
|
||||
end
|
||||
|
||||
def _serialize_template
|
||||
self.serialized_template = BSON::Binary.new(Marshal.dump(@template))
|
||||
end
|
||||
def update_template_descendants
|
||||
return unless @template_changed == true
|
||||
|
||||
def parse(context = {})
|
||||
self.disable_all_editable_elements
|
||||
# we admit at this point that the current template is up-to-date
|
||||
template_descendants = self.site.pages.any_in(:template_dependencies => [self.id]).to_a
|
||||
|
||||
default_context = { :site => self.site, :page => self, :templates => [], :snippets => [] }
|
||||
# group them by fullpath for better performance
|
||||
cached = template_descendants.inject({}) { |memo, page| memo[page.fullpath] = page; memo }
|
||||
|
||||
context = default_context.merge(context)
|
||||
self._update_direct_template_descendants(template_descendants.clone, cached)
|
||||
|
||||
@template = ::Liquid::Template.parse(self.raw_template, context)
|
||||
|
||||
self.template_dependencies = context[:templates]
|
||||
self.snippet_dependencies = context[:snippets]
|
||||
|
||||
@template.root.context.clear
|
||||
end
|
||||
|
||||
def template_must_be_valid
|
||||
@parsing_errors.try(:each) do |msg|
|
||||
self.errors.add :template, msg
|
||||
self.errors.add :raw_template, msg
|
||||
# finally save them all
|
||||
::Locomotive::Page.without_callback(:save, :after, :update_template_descendants) do
|
||||
template_descendants.each do |page|
|
||||
page.save(:validate => false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_template_descendants
|
||||
return unless @template_changed == true
|
||||
|
||||
# we admit at this point that the current template is up-to-date
|
||||
template_descendants = self.site.pages.any_in(:template_dependencies => [self.id]).to_a
|
||||
|
||||
# group them by fullpath for better performance
|
||||
cached = template_descendants.inject({}) { |memo, page| memo[page.fullpath] = page; memo }
|
||||
|
||||
self._update_direct_template_descendants(template_descendants.clone, cached)
|
||||
|
||||
# finally save them all
|
||||
::Locomotive::Page.without_callback(:save, :after, :update_template_descendants) do
|
||||
template_descendants.each do |page|
|
||||
page.save(:validate => false)
|
||||
end
|
||||
end
|
||||
def _update_direct_template_descendants(template_descendants, cached)
|
||||
direct_descendants = template_descendants.select do |page|
|
||||
((self.template_dependencies || []) + [self._id]) == (page.template_dependencies || [])
|
||||
end
|
||||
|
||||
def _update_direct_template_descendants(template_descendants, cached)
|
||||
direct_descendants = template_descendants.select do |page|
|
||||
((self.template_dependencies || []) + [self._id]) == (page.template_dependencies || [])
|
||||
end
|
||||
direct_descendants.each do |page|
|
||||
page.send(:_parse_and_serialize_template, { :cached_parent => self, :cached_pages => cached })
|
||||
|
||||
direct_descendants.each do |page|
|
||||
page.send(:_parse_and_serialize_template, { :cached_parent => self, :cached_pages => cached })
|
||||
template_descendants.delete(page) # no need to loop over it next time
|
||||
|
||||
template_descendants.delete(page) # no need to loop over it next time
|
||||
|
||||
page.send(:_update_direct_template_descendants, template_descendants, cached) # move down
|
||||
end
|
||||
page.send(:_update_direct_template_descendants, template_descendants, cached) # move down
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -7,19 +7,52 @@ module Locomotive
|
||||
|
||||
included do
|
||||
|
||||
belongs_to :content_type, :class_name => 'Locomotive::ContentType'
|
||||
|
||||
field :templatized, :type => Boolean, :default => false
|
||||
field :target_klass_name
|
||||
|
||||
field :content_type_visible_column
|
||||
## validations ##
|
||||
validates_presence_of :target_klass_name, :if => :templatized?
|
||||
validate :ensure_target_klass_name_security
|
||||
|
||||
## callbacks ##
|
||||
before_validation :set_slug_if_templatized
|
||||
before_validation :ensure_target_klass_name_security
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def target_klass
|
||||
target_klass_name.constantize
|
||||
end
|
||||
|
||||
def set_slug_if_templatized
|
||||
self.slug = 'content_type_template' if self.templatized?
|
||||
def target_entry_name
|
||||
if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
|
||||
@content_type ||= self.site.content_types.find($1)
|
||||
@content_type.slug.singularize
|
||||
else
|
||||
self.target_klass_name.underscore
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_target_entry(permalink)
|
||||
target_klass.find_by_permalink(permalink)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def set_slug_if_templatized
|
||||
self.slug = 'content_type_template' if self.templatized?
|
||||
end
|
||||
|
||||
def ensure_target_klass_name_security
|
||||
return if !self.templatized? || self.target_klass_name.blank?
|
||||
|
||||
if self.target_klass_name =~ /^Locomotive::Entry([a-z0-9]+)$/
|
||||
content_type = Locomotive::ContentType.find($1)
|
||||
|
||||
if content_type.site_id != self.site_id
|
||||
self.errors.add :target_klass_name, :security
|
||||
end
|
||||
elsif !Locomotive.config.models_for_templatization.include?(self.target_klass_name)
|
||||
self.errors.add :target_klass_name, :security
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -7,8 +7,12 @@ module Locomotive
|
||||
self.source.ordered_entries_custom_fields.collect(&:as_json)
|
||||
end
|
||||
|
||||
def klass_name
|
||||
self.source.klass_with_custom_fields(:entries).to_s
|
||||
end
|
||||
|
||||
def included_methods
|
||||
super + %w(name description slug order_by order_direction highlighted_field_name group_by_field_name api_accounts entries_custom_fields)
|
||||
super + %w(name description slug order_by order_direction highlighted_field_name group_by_field_name api_accounts entries_custom_fields klass_name)
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -30,10 +30,10 @@
|
||||
|
||||
= f.inputs :name => :advanced_options, :id => 'advanced-options', :class => "inputs foldable #{'folded' if inputs_folded?(@page)}" do
|
||||
|
||||
= f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
|
||||
|
||||
= f.input :templatized, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.redirect?}"
|
||||
|
||||
= f.input :target_klass_name, :as => :select, :collection => options_for_target_klass_name, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
|
||||
|
||||
= f.input :published, :as => :'Locomotive::Toggle'
|
||||
|
||||
= f.input :listed, :as => :'Locomotive::Toggle'
|
||||
|
@ -33,7 +33,7 @@ fr:
|
||||
extname_changed: "Nouveau fichier n'a pas l'extension original"
|
||||
array_too_short: "est trop petit (le nombre minimum d'éléments est %{count})"
|
||||
liquid_syntax: "Erreur de syntaxe ('%{error}')"
|
||||
invalid_theme_file: "doit être rempli ou n'est pas un fichier zip"
|
||||
security: "présente un problème de sécurité"
|
||||
page:
|
||||
liquid_syntax: "Erreur de syntaxe dans les sections de page, veuillez vérifier la syntaxe ('%{error}'/'%{fullpath}')"
|
||||
liquid_extend: "La page '%{fullpath}' étend le contenu d'une page qui n'existe pas"
|
||||
|
@ -54,6 +54,7 @@ en:
|
||||
password_confirmation: New password confirmation
|
||||
page:
|
||||
seo_title: Title
|
||||
target_klass_name: Model
|
||||
site:
|
||||
locales: Languages
|
||||
|
||||
@ -63,7 +64,7 @@ en:
|
||||
cache_strategy: "Cache the page for better performance. The 'Simple' choice is a good compromise."
|
||||
templatized: "Use the page as a template for a model you defined."
|
||||
listed: "Control whether to show the page from generated menus."
|
||||
content_type_id: "The type of content this page will be a template for."
|
||||
target_klass_name: "The type of content this page will be a template for."
|
||||
seo_title: "Define a page title which should be used as the value for the title tag in the head section. Leave it empty if you want to use the default value from the site settings."
|
||||
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."
|
||||
meta_description: "Overrides the site's meta description used within the head tag of the page."
|
||||
|
@ -51,7 +51,7 @@ Locomotive.configure do |config|
|
||||
# tell if logs are enabled. Useful for debug purpose.
|
||||
config.enable_logs = true
|
||||
|
||||
# Configure the e-mail address which will be shown in the DeviseMailer, NotificationMailer, ...etc
|
||||
# configure the e-mail address which will be shown in the DeviseMailer, NotificationMailer, ...etc
|
||||
# if you do not put the domain name in the email, Locomotive will take the default domain name depending
|
||||
# on your deployment target (server, Heroku, Bushido, ...etc)
|
||||
#
|
||||
@ -65,6 +65,9 @@ Locomotive.configure do |config|
|
||||
# follow the Dependency Injection pattern
|
||||
# config.context_assign_extensions = {}
|
||||
|
||||
# add extra classes other than the defined content types among a site which will potentially used by the templatized pages.
|
||||
# config.models_for_templatization = %w(Product)
|
||||
|
||||
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
|
||||
# config.rack_cache = {
|
||||
# :verbose => true,
|
||||
|
@ -43,7 +43,6 @@ module Locomotive
|
||||
end
|
||||
|
||||
def localized?
|
||||
Rails.logger.debug "localized? #{@locomotive_localized.inspect}"
|
||||
!!@locomotive_localized
|
||||
end
|
||||
|
||||
|
@ -27,7 +27,8 @@ module Locomotive
|
||||
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
|
||||
},
|
||||
:devise_modules => [:rememberable, :database_authenticatable, :token_authenticatable, :recoverable, :trackable, :validatable, :encryptable, { :encryptor => :sha1 }],
|
||||
:context_assign_extensions => { }
|
||||
:context_assign_extensions => { },
|
||||
:models_for_templatization => []
|
||||
}
|
||||
|
||||
cattr_accessor :settings
|
||||
|
@ -11,6 +11,10 @@ module Locomotive
|
||||
input.to_s.gsub(' ', '-').gsub('/', '-').dasherize
|
||||
end
|
||||
|
||||
def multi_line(input)
|
||||
input.to_s.gsub("\n", '<br/>')
|
||||
end
|
||||
|
||||
def concat(input, *args)
|
||||
result = input.to_s
|
||||
args.flatten.each { |a| result << a.to_s }
|
||||
@ -21,6 +25,14 @@ module Locomotive
|
||||
(index.to_i + 1) % modulo == 0 ? word : ''
|
||||
end
|
||||
|
||||
def first(input)
|
||||
input.first
|
||||
end
|
||||
|
||||
def last(input)
|
||||
input.last
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_filter(Misc)
|
||||
|
@ -3,126 +3,122 @@ module Locomotive
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module InstanceMethods
|
||||
protected
|
||||
|
||||
protected
|
||||
def render_locomotive_page
|
||||
if request.fullpath =~ /^\/admin\//
|
||||
render :template => '/locomotive/errors/404', :layout => '/admin/layouts/not_logged_in', :status => :not_found
|
||||
else
|
||||
@page = locomotive_page
|
||||
|
||||
def render_locomotive_page
|
||||
if request.fullpath =~ /^\/admin\//
|
||||
render :template => '/locomotive/errors/404', :layout => '/admin/layouts/not_logged_in', :status => :not_found
|
||||
redirect_to(@page.redirect_url) and return if @page.present? && @page.redirect?
|
||||
|
||||
render_no_page_error and return if @page.nil?
|
||||
|
||||
output = @page.render(locomotive_context)
|
||||
|
||||
self.prepare_and_set_response(output)
|
||||
end
|
||||
end
|
||||
|
||||
def render_no_page_error
|
||||
render :template => '/locomotive/errors/no_page', :layout => false
|
||||
end
|
||||
|
||||
def locomotive_page
|
||||
path = (params[:path] || params[:page_path] || request.fullpath).clone # TODO: params[:path] is more consistent
|
||||
path = path.split('?').first # take everything before the query string or the lookup fails
|
||||
path.gsub!(/\.[a-zA-Z][a-zA-Z0-9]{2,}$/, '') # remove the page extension
|
||||
path.gsub!(/^\//, '') # remove the leading slash
|
||||
|
||||
path = 'index' if path.blank? || path == '_edit'
|
||||
|
||||
if path != 'index'
|
||||
dirname = File.dirname(path).gsub(/^\.$/, '') # also look for templatized page path
|
||||
path = [path, File.join(dirname, 'content_type_template').gsub(/^\//, '')]
|
||||
end
|
||||
|
||||
if page = current_site.pages.any_in(:fullpath => [*path]).first
|
||||
if not page.published? and current_locomotive_account.nil?
|
||||
page = nil
|
||||
else
|
||||
@page = locomotive_page
|
||||
if page.templatized?
|
||||
@content_entry = page.fetch_target_entry(File.basename(path.first))
|
||||
|
||||
redirect_to(@page.redirect_url) and return if @page.present? && @page.redirect?
|
||||
|
||||
render_no_page_error and return if @page.nil?
|
||||
|
||||
output = @page.render(locomotive_context)
|
||||
|
||||
self.prepare_and_set_response(output)
|
||||
end
|
||||
end
|
||||
|
||||
def render_no_page_error
|
||||
render :template => '/locomotive/errors/no_page', :layout => false
|
||||
end
|
||||
|
||||
def locomotive_page
|
||||
path = (params[:path] || params[:page_path] || request.fullpath).clone # TODO: params[:path] is more consistent
|
||||
path = path.split('?').first # take everything before the query string or the lookup fails
|
||||
path.gsub!(/\.[a-zA-Z][a-zA-Z0-9]{2,}$/, '') # remove the page extension
|
||||
path.gsub!(/^\//, '') # remove the leading slash
|
||||
|
||||
path = 'index' if path.blank? || path == '_edit'
|
||||
|
||||
if path != 'index'
|
||||
dirname = File.dirname(path).gsub(/^\.$/, '') # also look for templatized page path
|
||||
path = [path, File.join(dirname, 'content_type_template').gsub(/^\//, '')]
|
||||
end
|
||||
|
||||
if page = current_site.pages.any_in(:fullpath => [*path]).first
|
||||
if not page.published? and current_locomotive_account.nil?
|
||||
page = nil
|
||||
else
|
||||
if page.templatized?
|
||||
@content_entry = page.content_type.entries.where(:_slug => File.basename(path.first)).first
|
||||
|
||||
if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible
|
||||
page = nil
|
||||
end
|
||||
if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible
|
||||
page = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page || not_found_page
|
||||
end
|
||||
|
||||
def locomotive_context
|
||||
assigns = {
|
||||
'site' => current_site,
|
||||
'page' => @page,
|
||||
'models' => Locomotive::Liquid::Drops::ContentTypes.new,
|
||||
'contents' => Locomotive::Liquid::Drops::ContentTypes.new, # DEPRECATED
|
||||
'current_page' => self.params[:page],
|
||||
'params' => self.params,
|
||||
'path' => request.path,
|
||||
'url' => request.url,
|
||||
'now' => Time.now.utc,
|
||||
'today' => Date.today,
|
||||
'locale' => I18n.locale,
|
||||
'default_locale' => current_site.default_locale.to_s,
|
||||
'locales' => current_site.locales
|
||||
}
|
||||
page || not_found_page
|
||||
end
|
||||
|
||||
assigns.merge!(Locomotive.config.context_assign_extensions)
|
||||
def locomotive_context
|
||||
assigns = {
|
||||
'site' => current_site,
|
||||
'page' => @page,
|
||||
'models' => Locomotive::Liquid::Drops::ContentTypes.new,
|
||||
'contents' => Locomotive::Liquid::Drops::ContentTypes.new, # DEPRECATED
|
||||
'current_page' => self.params[:page],
|
||||
'params' => self.params,
|
||||
'path' => request.path,
|
||||
'url' => request.url,
|
||||
'now' => Time.now.utc,
|
||||
'today' => Date.today,
|
||||
'locale' => I18n.locale,
|
||||
'default_locale' => current_site.default_locale.to_s,
|
||||
'locales' => current_site.locales
|
||||
}
|
||||
|
||||
assigns.merge!(flash.to_hash.stringify_keys) # data from public submissions
|
||||
assigns.merge!(Locomotive.config.context_assign_extensions)
|
||||
|
||||
if @page.templatized? # add instance from content type
|
||||
assigns['entry'] = @content_entry
|
||||
assigns[@page.content_type.slug.singularize] = @content_entry # just here to help to write readable liquid code
|
||||
assigns.merge!(flash.to_hash.stringify_keys) # data from public submissions
|
||||
|
||||
if @page.templatized? # add instance from content type
|
||||
assigns['entry'] = @content_entry
|
||||
assigns[@page.target_entry_name] = @content_entry # just here to help to write readable liquid code
|
||||
end
|
||||
|
||||
registers = {
|
||||
:controller => self,
|
||||
:site => current_site,
|
||||
:page => @page,
|
||||
:inline_editor => self.editing_page?,
|
||||
:current_locomotive_account => current_locomotive_account
|
||||
}
|
||||
|
||||
::Liquid::Context.new({}, assigns, registers, false) # switch from false to true to enable the re-thrown exception flag
|
||||
end
|
||||
|
||||
def prepare_and_set_response(output)
|
||||
flash.discard
|
||||
|
||||
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
||||
response.headers['Editable'] = 'true' unless self.editing_page?
|
||||
|
||||
if @page.with_cache?
|
||||
fresh_when :etag => @page, :last_modified => @page.updated_at.utc, :public => true
|
||||
|
||||
if @page.cache_strategy != 'simple' # varnish
|
||||
response.cache_control[:max_age] = @page.cache_strategy
|
||||
end
|
||||
|
||||
registers = {
|
||||
:controller => self,
|
||||
:site => current_site,
|
||||
:page => @page,
|
||||
:inline_editor => self.editing_page?,
|
||||
:current_locomotive_account => current_locomotive_account
|
||||
}
|
||||
|
||||
::Liquid::Context.new({}, assigns, registers, false) # switch from false to true to enable the re-thrown exception flag
|
||||
end
|
||||
|
||||
def prepare_and_set_response(output)
|
||||
flash.discard
|
||||
render :text => output, :layout => false, :status => page_status unless performed?
|
||||
end
|
||||
|
||||
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
||||
response.headers['Editable'] = 'true' unless self.editing_page?
|
||||
def not_found_page
|
||||
current_site.pages.not_found.published.first
|
||||
end
|
||||
|
||||
if @page.with_cache?
|
||||
fresh_when :etag => @page, :last_modified => @page.updated_at.utc, :public => true
|
||||
|
||||
if @page.cache_strategy != 'simple' # varnish
|
||||
response.cache_control[:max_age] = @page.cache_strategy
|
||||
end
|
||||
end
|
||||
|
||||
render :text => output, :layout => false, :status => page_status unless performed?
|
||||
end
|
||||
|
||||
def not_found_page
|
||||
current_site.pages.not_found.published.first
|
||||
end
|
||||
|
||||
def editing_page?
|
||||
!!@editing
|
||||
end
|
||||
|
||||
def page_status
|
||||
@page.not_found? ? :not_found : :ok
|
||||
end
|
||||
def editing_page?
|
||||
!!@editing
|
||||
end
|
||||
|
||||
def page_status
|
||||
@page.not_found? ? :not_found : :ok
|
||||
end
|
||||
|
||||
end
|
||||
|
7
spec/dummy/app/models/foo.rb
Normal file
7
spec/dummy/app/models/foo.rb
Normal file
@ -0,0 +1,7 @@
|
||||
class Foo
|
||||
|
||||
include Mongoid::Document
|
||||
|
||||
field :name
|
||||
|
||||
end
|
@ -66,6 +66,9 @@ Locomotive.configure do |config|
|
||||
# follow the Dependency Injection pattern
|
||||
# config.context_assign_extensions = {}
|
||||
|
||||
# add extra classes other than the defined content types among a site which will potentially used by the templatized pages.
|
||||
config.models_for_templatization = %w(Foo)
|
||||
|
||||
# Rack-cache settings, mainly used for the inline resizing image module. Default options:
|
||||
# config.rack_cache = {
|
||||
# :verbose => true,
|
||||
|
Loading…
Reference in New Issue
Block a user