wip
This commit is contained in:
parent
6bd1154886
commit
64168cad37
1
Gemfile
1
Gemfile
@ -8,6 +8,7 @@ gemspec # Include gemspec dependencies
|
||||
# The rest of the dependencies are for use when in the locomotive development environment
|
||||
|
||||
group :development do
|
||||
# gem 'locomotive-mongoid-tree', :path => '../gems/custom_fields' # for Developers
|
||||
# gem 'custom_fields', :path => '../gems/custom_fields' # for Developers
|
||||
gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => '2.0.0.rc' # Branch on Github
|
||||
|
||||
|
135
app/models/locomotive/extensions/page/fullpath.rb
Normal file
135
app/models/locomotive/extensions/page/fullpath.rb
Normal file
@ -0,0 +1,135 @@
|
||||
module Locomotive
|
||||
module Extensions
|
||||
module Page
|
||||
module Fullpath
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
|
||||
## fields ##
|
||||
field :fullpath, :localize => true
|
||||
field :wildcard, :type => Boolean, :default => false
|
||||
field :wildcards, :type => Array
|
||||
|
||||
## callbacks ##
|
||||
before_validation :get_wildcards_from_parent
|
||||
before_validation :add_slug_to_wildcards
|
||||
before_save :build_fullpath
|
||||
# before_rearrange :foo #propagate_fullpath_changes
|
||||
# after_save :propagate_fullpath_changes
|
||||
|
||||
## scopes ##
|
||||
# scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } } # used ?
|
||||
|
||||
## virtual attributes ##
|
||||
attr_accessor :wildcards_map
|
||||
|
||||
end
|
||||
|
||||
# def foo
|
||||
# Rails.logger.debug "----> rearranging #{self.slug}.......\n\n"
|
||||
# puts "[rearranging]"
|
||||
# end
|
||||
|
||||
# This method returns true if the fullpath is enhanced
|
||||
# by wildcards. It is different from the wildcard? method
|
||||
# because it includes the ancestors when determining if
|
||||
# the current page has wildcards or not.
|
||||
#
|
||||
def has_wildcards?
|
||||
!self.fullpath.try(:index, '*').nil?
|
||||
end
|
||||
|
||||
# It returns a pretty output of the fullpath. The "*" characters
|
||||
# are replaced by the following pattern ":<slug>" like you can find
|
||||
# in the Ruby on Rails routes.
|
||||
#
|
||||
def pretty_fullpath
|
||||
return self.fullpath unless self.has_wildcards?
|
||||
|
||||
index = 0
|
||||
|
||||
self.fullpath.split('/').map do |segment|
|
||||
if segment == '*'
|
||||
":#{self.wildcards[index]}".tap { index += 1 }
|
||||
else
|
||||
segment
|
||||
end
|
||||
end.join('/')
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def get_wildcards_from_parent
|
||||
return true if self.parent.nil?
|
||||
|
||||
if self.parent.has_wildcards?
|
||||
puts "[get_wildcards_from_parent] #{self.slug} - #{self.parent.wildcards.inspect}"
|
||||
self.wildcards = self.parent.wildcards
|
||||
elsif !self.wildcard?
|
||||
self.wildcards = nil
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def add_slug_to_wildcards
|
||||
(self.wildcards ||= []) << self.slug if self.wildcard?
|
||||
end
|
||||
|
||||
def build_fullpath
|
||||
if self.index? || self.not_found?
|
||||
self.fullpath = self.slug
|
||||
else
|
||||
slugs = self.ancestors_and_self.map { |page| page.wildcard? ? '*' : page.slug }
|
||||
slugs.shift unless slugs.size == 1
|
||||
self.fullpath = File.join slugs.compact
|
||||
end
|
||||
end
|
||||
|
||||
def propagate_fullpath_changes
|
||||
return true unless self.wildcard_changed? || self.slug_changed?
|
||||
|
||||
parent_identities = { self._id => self }
|
||||
|
||||
Rails.logger.debug "[propagate_fullpath_changes] BEGIN page #{self.slug} #{self.fullpath} / #{self.wildcards.inspect} / #{self._parent.try(:has_wildcards?).inspect}"
|
||||
puts "[propagate_fullpath_changes] BEGIN page #{self.slug} #{self.fullpath} / #{self.wildcards.inspect} / #{self._parent.try(:has_wildcards?).inspect}"
|
||||
|
||||
self.descendants.order_by([[:depth, :asc]]).each do |page|
|
||||
_parent = parent_identities[page.parent_id]
|
||||
_fullpath = {}
|
||||
_wildcards = nil
|
||||
|
||||
puts "[propagate_fullpath_changes] #{page.fullpath} / #{page.wildcards.inspect} / #{page._parent.try(:has_wildcards?).inspect}"
|
||||
|
||||
if _parent.has_wildcards?
|
||||
_wildcards = _parent.wildcards + (page.wildcard? ? [page.slug] : [])
|
||||
end
|
||||
|
||||
self.site.locales.each do |locale|
|
||||
base_fullpath = _parent.fullpath_translations[locale]
|
||||
slug = page.wildcard? ? '*' : page.slug_translations[locale]
|
||||
|
||||
next if base_fullpath.blank?
|
||||
|
||||
_fullpath[locale] = File.join(base_fullpath, slug)
|
||||
end
|
||||
|
||||
selector = { 'id' => page._id }
|
||||
operations = {
|
||||
'$set' => {
|
||||
'wildcards' => _wildcards,
|
||||
'fullpath' => _fullpath
|
||||
}
|
||||
}
|
||||
self.collection.update selector, operations
|
||||
|
||||
parent_identities[page._id] = page
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -22,7 +22,8 @@ module Locomotive
|
||||
validate :template_must_be_valid
|
||||
|
||||
## scopes ##
|
||||
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||
scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } }
|
||||
end
|
||||
|
||||
def template
|
||||
|
@ -56,9 +56,7 @@ module Locomotive
|
||||
|
||||
# Calculate all the combinations possible based on the
|
||||
# fact that one of the segment of the path could be
|
||||
# a content type from a templatized page.
|
||||
# We postulate that there is only one templatized page in a path
|
||||
# (ie: no nested templatized pages)
|
||||
# a wildcard.
|
||||
#
|
||||
# @param [ String ] path The path to the page
|
||||
#
|
||||
@ -69,13 +67,13 @@ module Locomotive
|
||||
end
|
||||
|
||||
#:nodoc:
|
||||
def _path_combinations(segments, can_include_template = true)
|
||||
def _path_combinations(segments)
|
||||
return nil if segments.empty?
|
||||
|
||||
segment = segments.shift
|
||||
|
||||
(can_include_template ? [segment, 'content_type_template'] : [segment]).map do |_segment|
|
||||
if (_combinations = _path_combinations(segments.clone, can_include_template && _segment != 'content_type_template'))
|
||||
[segment, '*'].map do |_segment|
|
||||
if (_combinations = _path_combinations(segments.clone))
|
||||
[*_combinations].map do |_combination|
|
||||
File.join(_segment, _combination)
|
||||
end
|
||||
|
@ -1,136 +1,136 @@
|
||||
module Locomotive
|
||||
module Extensions
|
||||
module Page
|
||||
module Templatized
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
|
||||
## fields ##
|
||||
field :templatized, :type => Boolean, :default => false
|
||||
field :templatized_from_parent, :type => Boolean, :default => false
|
||||
field :target_klass_name
|
||||
|
||||
## validations ##
|
||||
validates_presence_of :target_klass_name, :if => :templatized?
|
||||
validate :ensure_target_klass_name_security
|
||||
|
||||
## callbacks ##
|
||||
before_validation :get_templatized_from_parent
|
||||
before_validation :set_slug_if_templatized
|
||||
before_validation :ensure_target_klass_name_security
|
||||
after_save :propagate_templatized
|
||||
|
||||
## scopes ##
|
||||
scope :templatized, :where => { :templatized => true }
|
||||
|
||||
## virtual attributes ##
|
||||
attr_accessor :content_entry
|
||||
end
|
||||
|
||||
# Returns the class specified by the target_klass_name property
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# page.target_klass_name = 'Locomotive::Entry12345'
|
||||
# page.target_klass = Locomotive::Entry12345
|
||||
#
|
||||
# @return [ Class ] The target class
|
||||
#
|
||||
def target_klass
|
||||
target_klass_name.constantize
|
||||
end
|
||||
|
||||
# Gives the name which can be used in a liquid template in order
|
||||
# to reference an entry. It uses the slug property if the target klass
|
||||
# is a Locomotive content type or the class name itself for the other classes.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles
|
||||
# page.target_entry_name = 'article'
|
||||
#
|
||||
# page.target_klass_name = 'OurProduct'
|
||||
# page.target_entry_name = 'our_product'
|
||||
#
|
||||
# @return [ String ] The name in lowercase and underscored
|
||||
#
|
||||
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
|
||||
|
||||
# Finds the entry both specified by the target klass and identified by the permalink
|
||||
#
|
||||
# @param [ String ] permalink The permalink of the entry
|
||||
#
|
||||
# @return [ Object ] The document
|
||||
#
|
||||
def fetch_target_entry(permalink)
|
||||
target_klass.find_by_permalink(permalink)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def get_templatized_from_parent
|
||||
return if self.parent.nil?
|
||||
|
||||
if self.parent.templatized?
|
||||
self.templatized = self.templatized_from_parent = true
|
||||
self.target_klass_name = self.parent.target_klass_name
|
||||
elsif !self.templatized?
|
||||
self.templatized = self.templatized_from_parent = false
|
||||
self.target_klass_name = nil
|
||||
end
|
||||
end
|
||||
|
||||
def set_slug_if_templatized
|
||||
self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent?
|
||||
end
|
||||
|
||||
# Makes sure the target_klass is owned by the site OR
|
||||
# if it belongs to the models allowed by the application
|
||||
# thanks to the models_for_templatization option.
|
||||
#
|
||||
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
|
||||
|
||||
# Sets the templatized, templatized_from_parent properties of
|
||||
# the children of the current page ONLY IF the templatized
|
||||
# attribute got changed.
|
||||
#
|
||||
def propagate_templatized
|
||||
return unless self.templatized_changed?
|
||||
|
||||
selector = { 'parent_ids' => { '$in' => [self._id] } }
|
||||
operations = {
|
||||
'$set' => {
|
||||
'templatized' => self.templatized,
|
||||
'templatized_from_parent' => self.templatized,
|
||||
'target_klass_name' => self.target_klass_name
|
||||
}
|
||||
}
|
||||
|
||||
self.collection.update selector, operations, :multi => true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# module Locomotive
|
||||
# module Extensions
|
||||
# module Page
|
||||
# module Templatized
|
||||
#
|
||||
# extend ActiveSupport::Concern
|
||||
#
|
||||
# included do
|
||||
#
|
||||
# ## fields ##
|
||||
# field :templatized, :type => Boolean, :default => false
|
||||
# field :templatized_from_parent, :type => Boolean, :default => false
|
||||
# field :target_klass_name
|
||||
#
|
||||
# ## validations ##
|
||||
# validates_presence_of :target_klass_name, :if => :templatized?
|
||||
# validate :ensure_target_klass_name_security
|
||||
#
|
||||
# ## callbacks ##
|
||||
# before_validation :get_templatized_from_parent
|
||||
# before_validation :set_slug_if_templatized
|
||||
# before_validation :ensure_target_klass_name_security
|
||||
# after_save :propagate_templatized
|
||||
#
|
||||
# ## scopes ##
|
||||
# scope :templatized, :where => { :templatized => true }
|
||||
#
|
||||
# ## virtual attributes ##
|
||||
# attr_accessor :content_entry
|
||||
# end
|
||||
#
|
||||
# # Returns the class specified by the target_klass_name property
|
||||
# #
|
||||
# # @example
|
||||
# #
|
||||
# # page.target_klass_name = 'Locomotive::Entry12345'
|
||||
# # page.target_klass = Locomotive::Entry12345
|
||||
# #
|
||||
# # @return [ Class ] The target class
|
||||
# #
|
||||
# def target_klass
|
||||
# target_klass_name.constantize
|
||||
# end
|
||||
#
|
||||
# # Gives the name which can be used in a liquid template in order
|
||||
# # to reference an entry. It uses the slug property if the target klass
|
||||
# # is a Locomotive content type or the class name itself for the other classes.
|
||||
# #
|
||||
# # @example
|
||||
# #
|
||||
# # page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles
|
||||
# # page.target_entry_name = 'article'
|
||||
# #
|
||||
# # page.target_klass_name = 'OurProduct'
|
||||
# # page.target_entry_name = 'our_product'
|
||||
# #
|
||||
# # @return [ String ] The name in lowercase and underscored
|
||||
# #
|
||||
# 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
|
||||
#
|
||||
# # Finds the entry both specified by the target klass and identified by the permalink
|
||||
# #
|
||||
# # @param [ String ] permalink The permalink of the entry
|
||||
# #
|
||||
# # @return [ Object ] The document
|
||||
# #
|
||||
# def fetch_target_entry(permalink)
|
||||
# target_klass.find_by_permalink(permalink)
|
||||
# end
|
||||
#
|
||||
# protected
|
||||
#
|
||||
# def get_templatized_from_parent
|
||||
# return if self.parent.nil?
|
||||
#
|
||||
# if self.parent.templatized?
|
||||
# self.templatized = self.templatized_from_parent = true
|
||||
# self.target_klass_name = self.parent.target_klass_name
|
||||
# elsif !self.templatized?
|
||||
# self.templatized = self.templatized_from_parent = false
|
||||
# self.target_klass_name = nil
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def set_slug_if_templatized
|
||||
# self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent?
|
||||
# end
|
||||
#
|
||||
# # Makes sure the target_klass is owned by the site OR
|
||||
# # if it belongs to the models allowed by the application
|
||||
# # thanks to the models_for_templatization option.
|
||||
# #
|
||||
# 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
|
||||
#
|
||||
# # Sets the templatized, templatized_from_parent properties of
|
||||
# # the children of the current page ONLY IF the templatized
|
||||
# # attribute got changed.
|
||||
# #
|
||||
# def propagate_templatized
|
||||
# return unless self.templatized_changed?
|
||||
#
|
||||
# selector = { 'parent_ids' => { '$in' => [self._id] } }
|
||||
# operations = {
|
||||
# '$set' => {
|
||||
# 'templatized' => self.templatized,
|
||||
# 'templatized_from_parent' => self.templatized,
|
||||
# 'target_klass_name' => self.target_klass_name
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# self.collection.update selector, operations, :multi => true
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
213
app/models/locomotive/extensions/page/wildcards.rb
Normal file
213
app/models/locomotive/extensions/page/wildcards.rb
Normal file
@ -0,0 +1,213 @@
|
||||
# module Locomotive
|
||||
# module Extensions
|
||||
# module Page
|
||||
# module Templatized
|
||||
#
|
||||
# extend ActiveSupport::Concern
|
||||
#
|
||||
# included do
|
||||
#
|
||||
# ## fields ##
|
||||
# field :wildcards, :type => Array
|
||||
# field :with_wildcards, :type => Boolean, :default => false
|
||||
# field :fullpath_with_wildcards, :default => false, :localize => true
|
||||
#
|
||||
# ## callbacks ##
|
||||
# before_validation :get_wildcards_from_parent
|
||||
# before_validation :add_slug_to_wildcards
|
||||
# before_save :build_fullpath_with_wildcards
|
||||
# after_save :propagate_wildcards
|
||||
#
|
||||
# ## scopes ##
|
||||
#
|
||||
# ## virtual attributes ##
|
||||
# attr_accessor :wildcards_map
|
||||
#
|
||||
# end
|
||||
#
|
||||
# protected
|
||||
#
|
||||
# def get_wildcards_from_parent
|
||||
# return if self.parent.nil?
|
||||
#
|
||||
# if self.parent.with_wildcards?
|
||||
# self.wildcards = self.parent.wildcards
|
||||
# self.with_wildcards = true
|
||||
# elsif !self.with_wildcards?
|
||||
# self.wildcards = []
|
||||
# self.with_wildcards = false
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def add_slug_to_wildcards
|
||||
# (self.wildcards ||= []) << self.slug if self.will_wildcards?
|
||||
# end
|
||||
#
|
||||
# def build_fullpath_with_wildcards
|
||||
# if self.index? || self.not_found?
|
||||
# self.fullpath_with_wildcards = self.slug
|
||||
# else
|
||||
# slugs = self.ancestors_and_self.map { |page| page.with_wildcards? ? '*' : page.slug }
|
||||
# slugs.shift unless slugs.size == 1
|
||||
# self.fullpath_with_wildcards = File.join slugs.compact
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# def propagate_wildcards
|
||||
# return unless self.with_wildcards_changed? || (self.with_wildcards? && self.slug_changed?)
|
||||
#
|
||||
# parent_identities = { self._id => self }
|
||||
#
|
||||
# self.descendants.order_by([[:depth, :asc]]).each do |page|
|
||||
# _parent = parent_identities[page._id]
|
||||
# _wildcards = _parent.wildcards + (page.wildcards? ? [page.slug] : [])
|
||||
# _fullpath_with_wildcards = File.join(_parent.fullpath_with_wildcards, page.wildcards? ? '*' : page.slug)
|
||||
#
|
||||
# # TODO: fullpath_with_wildcards is localized !!!!
|
||||
#
|
||||
# selector = { 'id' => page._id }
|
||||
# operations = {
|
||||
# '$set' => {
|
||||
# 'wildcards' => _wildcards,
|
||||
# 'with_wildcards' => true,
|
||||
# 'fullpath_with_wildcards' => _fullpath_with_wildcards
|
||||
# }
|
||||
# }
|
||||
# self.collection.update selector, operations
|
||||
#
|
||||
# parent_identities[page._id] = page
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
#
|
||||
# # field :templatized_from_parent, :type => Boolean, :default => false
|
||||
# # field :target_klass_name
|
||||
# #
|
||||
# # ## validations ##
|
||||
# # validates_presence_of :target_klass_name, :if => :templatized?
|
||||
# # validate :ensure_target_klass_name_security
|
||||
# #
|
||||
# # ## callbacks ##
|
||||
# # before_validation :get_templatized_from_parent
|
||||
# # before_validation :set_slug_if_templatized
|
||||
# # before_validation :ensure_target_klass_name_security
|
||||
# # after_save :propagate_templatized
|
||||
# #
|
||||
# # ## scopes ##
|
||||
# # scope :templatized, :where => { :templatized => true }
|
||||
# #
|
||||
# # ## virtual attributes ##
|
||||
# # attr_accessor :content_entry
|
||||
# # end
|
||||
# #
|
||||
# # # Returns the class specified by the target_klass_name property
|
||||
# # #
|
||||
# # # @example
|
||||
# # #
|
||||
# # # page.target_klass_name = 'Locomotive::Entry12345'
|
||||
# # # page.target_klass = Locomotive::Entry12345
|
||||
# # #
|
||||
# # # @return [ Class ] The target class
|
||||
# # #
|
||||
# # def target_klass
|
||||
# # target_klass_name.constantize
|
||||
# # end
|
||||
# #
|
||||
# # # Gives the name which can be used in a liquid template in order
|
||||
# # # to reference an entry. It uses the slug property if the target klass
|
||||
# # # is a Locomotive content type or the class name itself for the other classes.
|
||||
# # #
|
||||
# # # @example
|
||||
# # #
|
||||
# # # page.target_klass_name = 'Locomotive::Entry12345' # related to the content type Articles
|
||||
# # # page.target_entry_name = 'article'
|
||||
# # #
|
||||
# # # page.target_klass_name = 'OurProduct'
|
||||
# # # page.target_entry_name = 'our_product'
|
||||
# # #
|
||||
# # # @return [ String ] The name in lowercase and underscored
|
||||
# # #
|
||||
# # 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
|
||||
# #
|
||||
# # # Finds the entry both specified by the target klass and identified by the permalink
|
||||
# # #
|
||||
# # # @param [ String ] permalink The permalink of the entry
|
||||
# # #
|
||||
# # # @return [ Object ] The document
|
||||
# # #
|
||||
# # def fetch_target_entry(permalink)
|
||||
# # target_klass.find_by_permalink(permalink)
|
||||
# # end
|
||||
# #
|
||||
# # protected
|
||||
# #
|
||||
# # def get_templatized_from_parent
|
||||
# # return if self.parent.nil?
|
||||
# #
|
||||
# # if self.parent.templatized?
|
||||
# # self.templatized = self.templatized_from_parent = true
|
||||
# # self.target_klass_name = self.parent.target_klass_name
|
||||
# # elsif !self.templatized?
|
||||
# # self.templatized = self.templatized_from_parent = false
|
||||
# # self.target_klass_name = nil
|
||||
# # end
|
||||
# # end
|
||||
# #
|
||||
# # def set_slug_if_templatized
|
||||
# # self.slug = 'content_type_template' if self.templatized? && !self.templatized_from_parent?
|
||||
# # end
|
||||
# #
|
||||
# # # Makes sure the target_klass is owned by the site OR
|
||||
# # # if it belongs to the models allowed by the application
|
||||
# # # thanks to the models_for_templatization option.
|
||||
# # #
|
||||
# # 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
|
||||
# #
|
||||
# # # Sets the templatized, templatized_from_parent properties of
|
||||
# # # the children of the current page ONLY IF the templatized
|
||||
# # # attribute got changed.
|
||||
# # #
|
||||
# # def propagate_templatized
|
||||
# # return unless self.templatized_changed?
|
||||
# #
|
||||
# # selector = { 'parent_ids' => { '$in' => [self._id] } }
|
||||
# # operations = {
|
||||
# # '$set' => {
|
||||
# # 'templatized' => self.templatized,
|
||||
# # 'templatized_from_parent' => self.templatized,
|
||||
# # 'target_klass_name' => self.target_klass_name
|
||||
# # }
|
||||
# # }
|
||||
# #
|
||||
# # self.collection.update selector, operations, :multi => true
|
||||
# # end
|
||||
# #
|
||||
# # end
|
||||
# # end
|
||||
# # end
|
||||
# # end
|
@ -8,7 +8,7 @@ module Locomotive
|
||||
include Extensions::Page::EditableElements
|
||||
include Extensions::Page::Parse
|
||||
include Extensions::Page::Render
|
||||
include Extensions::Page::Templatized
|
||||
include Extensions::Page::Fullpath
|
||||
include Extensions::Page::Redirect
|
||||
include Extensions::Page::Listed
|
||||
include Extensions::Shared::Seo
|
||||
@ -16,7 +16,6 @@ module Locomotive
|
||||
## fields ##
|
||||
field :title, :localize => true
|
||||
field :slug, :localize => true
|
||||
field :fullpath, :localize => true
|
||||
field :handle
|
||||
field :raw_template, :localize => true
|
||||
field :locales, :type => Array
|
||||
@ -35,7 +34,6 @@ module Locomotive
|
||||
## callbacks ##
|
||||
after_initialize :set_default_raw_template
|
||||
before_validation :normalize_slug
|
||||
before_save :build_fullpath
|
||||
before_save :record_current_locale
|
||||
before_destroy :do_not_remove_index_and_404_pages
|
||||
|
||||
@ -50,10 +48,8 @@ module Locomotive
|
||||
scope :root, :where => { :slug => 'index', :depth => 0 }
|
||||
scope :not_found, :where => { :slug => '404', :depth => 0 }
|
||||
scope :published, :where => { :published => true }
|
||||
scope :fullpath, lambda { |fullpath| { :where => { :fullpath => fullpath } } }
|
||||
scope :handle, lambda { |handle| { :where => { :handle => handle } } }
|
||||
scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published templatized redirect listed response_type parent_id site_id created_at updated_at) } }
|
||||
scope :dependent_from, lambda { |id| { :where => { :template_dependencies.in => [id] } } }
|
||||
scope :minimal_attributes, lambda { |attrs = []| { :only => (attrs || []) + %w(title slug fullpath position depth published with_wildcards redirect listed response_type parent_id site_id created_at updated_at) } }
|
||||
|
||||
## methods ##
|
||||
|
||||
@ -114,16 +110,6 @@ module Locomotive
|
||||
self.raw_template ||= ::I18n.t('attributes.defaults.pages.other.body')
|
||||
end
|
||||
|
||||
def build_fullpath
|
||||
if self.index? || self.not_found?
|
||||
self.fullpath = self.slug
|
||||
else
|
||||
slugs = self.ancestors_and_self.map(&:slug)
|
||||
slugs.shift unless slugs.size == 1
|
||||
self.fullpath = File.join slugs.compact
|
||||
end
|
||||
end
|
||||
|
||||
def record_current_locale
|
||||
self.locales ||= []
|
||||
self.locales << ::Mongoid::Fields::I18n.locale
|
||||
|
@ -5,15 +5,15 @@ rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
|
||||
Locomotive::Page.each do |page|
|
||||
page.editable_elements.each_with_index do |el, index|
|
||||
next if el._type != 'Locomotive::EditableFile' || el.attributes['source'].is_a?(Hash)
|
||||
|
||||
value = el.attributes['source']
|
||||
|
||||
page.collection.update({ '_id' => page._id }, { '$set' => { "editable_elements.#{index}.source" => { 'en' => value } } })
|
||||
end
|
||||
end
|
||||
# Locomotive::Page.each do |page|
|
||||
# page.editable_elements.each_with_index do |el, index|
|
||||
# next if el._type != 'Locomotive::EditableFile' || el.attributes['source'].is_a?(Hash)
|
||||
#
|
||||
# value = el.attributes['source']
|
||||
#
|
||||
# page.collection.update({ '_id' => page._id }, { '$set' => { "editable_elements.#{index}.source" => { 'en' => value } } })
|
||||
# end
|
||||
# end
|
||||
|
||||
|
||||
# ================ GLOBAL VARIABLES ==============
|
||||
|
135
spec/models/locomotive/extensions/page/fullpath_spec.rb
Normal file
135
spec/models/locomotive/extensions/page/fullpath_spec.rb
Normal file
@ -0,0 +1,135 @@
|
||||
# coding: utf-8
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Page do
|
||||
|
||||
before(:each) do
|
||||
Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true)
|
||||
Locomotive::Page.any_instance.stubs(:set_default_raw_template).returns(true)
|
||||
end
|
||||
|
||||
describe 'wildcards' do
|
||||
|
||||
before(:each) do
|
||||
@page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page), :title => 'Project template', :slug => 'permalink', :wildcard => true)
|
||||
end
|
||||
|
||||
it 'has a fullpath with wildcards' do
|
||||
@page.wildcard?.should be_true
|
||||
end
|
||||
|
||||
it 'returns a nice output of the fullpath' do
|
||||
@page.fullpath = 'archives/*/projects/*'
|
||||
@page.wildcards = %w(month permalink)
|
||||
@page.pretty_fullpath.should == 'archives/:month/projects/:permalink'
|
||||
end
|
||||
|
||||
describe 'building the fullpath' do
|
||||
|
||||
it 'returns "index" for the root page' do
|
||||
@page = FactoryGirl.build(:page)
|
||||
@page.send(:build_fullpath)
|
||||
@page.fullpath.should == 'index'
|
||||
end
|
||||
|
||||
it 'returns "404" for the "page not found" page' do
|
||||
@page = FactoryGirl.build(:page, :slug => '404')
|
||||
@page.send(:build_fullpath)
|
||||
@page.fullpath.should == '404'
|
||||
end
|
||||
|
||||
it 'includes a single "*" if the page enables wildcards' do
|
||||
@page.send(:build_fullpath)
|
||||
@page.fullpath.should == '*'
|
||||
end
|
||||
|
||||
it 'includes a single "*" if the page enables wildcards and if there are a lot of ancestors' do
|
||||
@page.stubs(:ancestors_and_self).returns([FactoryGirl.build(:page), FactoryGirl.build(:page, :slug => 'archives'), FactoryGirl.build(:page, :slug => 'projects'), @page])
|
||||
@page.send(:build_fullpath)
|
||||
@page.fullpath.should == 'archives/projects/*'
|
||||
end
|
||||
|
||||
it 'includes many "*" when there are ancestors enabling wildcards' do
|
||||
@page.stubs(:ancestors_and_self).returns([FactoryGirl.build(:page),
|
||||
FactoryGirl.build(:page, :slug => 'archives'),
|
||||
FactoryGirl.build(:page, :slug => 'month', :wildcard => true),
|
||||
FactoryGirl.build(:page, :slug => 'projects'), @page])
|
||||
@page.send(:build_fullpath)
|
||||
@page.fullpath.should == 'archives/*/projects/*'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'adding wildcards' do
|
||||
|
||||
it 'fills the array of wildcards' do
|
||||
@page.valid?
|
||||
@page.wildcards.should == %w(permalink)
|
||||
end
|
||||
|
||||
it 'fills the array of wildcards from ancestors' do
|
||||
@page.parent.stubs(:has_wildcards?).returns(true)
|
||||
@page.parent.wildcards = %w(category month)
|
||||
@page.valid?
|
||||
@page.wildcards.should == %w(category month permalink)
|
||||
end
|
||||
|
||||
it 'contains a array of valid wildcards' do
|
||||
@page.slug = 'another permalink'
|
||||
@page.valid?
|
||||
@page.wildcards.should == %w(another-permalink)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'propagating changes' do
|
||||
|
||||
before(:each) do
|
||||
@home_page = FactoryGirl.create(:page)
|
||||
@archives_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @home_page, :slug => 'archives')
|
||||
@month_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @archives_page, :slug => 'month')
|
||||
@projects_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @month_page, :slug => 'projects')
|
||||
@project_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @projects_page, :slug => 'project', :wildcard => true)
|
||||
@posts_page = FactoryGirl.create(:page, :site => @home_page.site, :parent => @month_page, :slug => 'posts')
|
||||
end
|
||||
|
||||
it 'keeps the wildcards as they were if we modify a slug of an ancestor' do
|
||||
@archives_page.update_attributes :slug => 'my_archives'
|
||||
@project_page.reload
|
||||
@project_page.fullpath.should == 'my_archives/month/projects/*'
|
||||
end
|
||||
|
||||
it 'turns a page into a wildcards one' do
|
||||
Rails.logger.debug "=========== START ============"
|
||||
@month_page.update_attributes :wildcard => true
|
||||
Rails.logger.debug "=========== END ============"
|
||||
@project_page.reload
|
||||
@project_page.fullpath.should == 'archives/*/projects/*'
|
||||
@posts_page.reload
|
||||
@posts_page.fullpath.should == 'archives/*/posts'
|
||||
end
|
||||
|
||||
it 'turns off the wildcard property of page' do
|
||||
puts "==== 1 ==="
|
||||
Rails.logger.debug "==== 1 ==="
|
||||
puts "@month_page = #{@month_page.fullpath.inspect} / #{@month_page.wildcards.inspect}"
|
||||
@month_page.update_attributes :wildcard => true
|
||||
puts "==== 2 === "
|
||||
Rails.logger.debug "==== 2 ==="
|
||||
@month_page.update_attributes :wildcard => false
|
||||
puts "---- DONE ----"
|
||||
Rails.logger.debug "==== DONE ==="
|
||||
@project_page.reload
|
||||
@project_page.fullpath.should == 'archives/month/projects/*'
|
||||
@project_page.wildcards.should == %w(project)
|
||||
@posts_page.reload
|
||||
@posts_page.fullpath.should == 'archives/month/posts'
|
||||
@posts_page.wildcards.should == nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
@ -223,108 +223,108 @@ describe Locomotive::Page do
|
||||
|
||||
end
|
||||
|
||||
describe 'templatized extension' do
|
||||
|
||||
before(:each) do
|
||||
@page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page, :templatized => false), :templatized => true, :target_klass_name => 'Foo')
|
||||
end
|
||||
|
||||
it 'is considered as a templatized page' do
|
||||
@page.templatized?.should be_true
|
||||
end
|
||||
|
||||
it 'fills in the slug field' do
|
||||
@page.valid?
|
||||
@page.slug.should == 'content_type_template'
|
||||
end
|
||||
|
||||
it 'returns the target klass' do
|
||||
@page.target_klass.should == Foo
|
||||
end
|
||||
|
||||
it 'has a name for the target entry' do
|
||||
@page.target_entry_name.should == 'foo'
|
||||
end
|
||||
|
||||
it 'uses the find_by_permalink method when fetching the entry' do
|
||||
Foo.expects(:find_by_permalink)
|
||||
@page.fetch_target_entry('foo')
|
||||
end
|
||||
|
||||
context '#descendants' do
|
||||
|
||||
before(:each) do
|
||||
@home = FactoryGirl.create(:page)
|
||||
@page.attributes = { :parent_id => @home._id, :site => @home.site }; @page.save!
|
||||
@sub_page = FactoryGirl.build(:page, :title => 'Subpage', :slug => 'foo', :parent => @page, :site => @home.site, :templatized => false)
|
||||
end
|
||||
|
||||
it 'inherits the templatized property from its parent' do
|
||||
@sub_page.valid?
|
||||
@sub_page.templatized?.should be_true
|
||||
@sub_page.templatized_from_parent?.should be_true
|
||||
@sub_page.target_klass_name.should == 'Foo'
|
||||
end
|
||||
|
||||
it 'gets templatized if its parent is' do
|
||||
@page.attributes = { :templatized => false, :target_klass_name => nil }; @page.save!
|
||||
@sub_page.save.should be_true
|
||||
@sub_page.templatized?.should be_false
|
||||
|
||||
@page.attributes = { :templatized => true, :target_klass_name => 'Foo' }; @page.save!
|
||||
@sub_page.reload
|
||||
@sub_page.templatized?.should be_true
|
||||
@sub_page.templatized_from_parent?.should be_true
|
||||
@sub_page.target_klass_name.should == 'Foo'
|
||||
end
|
||||
|
||||
it 'is not templatized if its parent is no more a templatized page' do
|
||||
@sub_page.save.should be_true
|
||||
@page.templatized = false; @page.save!
|
||||
@sub_page.reload
|
||||
@sub_page.templatized.should be_false
|
||||
@sub_page.templatized_from_parent.should be_false
|
||||
@sub_page.target_klass_name.should be_nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'using a content type' do
|
||||
|
||||
before(:each) do
|
||||
@site = FactoryGirl.build(:site)
|
||||
@content_type = FactoryGirl.build(:content_type, :slug => 'posts', :site => @site)
|
||||
@page.site = @site
|
||||
@page.target_klass_name = 'Locomotive::Entry42'
|
||||
end
|
||||
|
||||
it 'has a name for the target entry' do
|
||||
@site.stubs(:content_types).returns(mock(:find => @content_type))
|
||||
@page.target_entry_name.should == 'post'
|
||||
end
|
||||
|
||||
context '#security' do
|
||||
|
||||
before(:each) do
|
||||
Locomotive::ContentType.stubs(:find).returns(@content_type)
|
||||
end
|
||||
|
||||
it 'is valid if the content type belongs to the site' do
|
||||
@page.send(:ensure_target_klass_name_security)
|
||||
@page.errors.should be_empty
|
||||
end
|
||||
|
||||
it 'does not valid the page if the content type does not belong to the site' do
|
||||
@content_type.site = FactoryGirl.build(:site)
|
||||
@page.send(:ensure_target_klass_name_security)
|
||||
@page.errors[:target_klass_name].should == ['presents a security problem']
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
# describe 'templatized extension' do
|
||||
#
|
||||
# before(:each) do
|
||||
# @page = FactoryGirl.build(:page, :parent => FactoryGirl.build(:page, :templatized => false), :templatized => true, :target_klass_name => 'Foo')
|
||||
# end
|
||||
#
|
||||
# it 'is considered as a templatized page' do
|
||||
# @page.templatized?.should be_true
|
||||
# end
|
||||
#
|
||||
# it 'fills in the slug field' do
|
||||
# @page.valid?
|
||||
# @page.slug.should == 'content_type_template'
|
||||
# end
|
||||
#
|
||||
# it 'returns the target klass' do
|
||||
# @page.target_klass.should == Foo
|
||||
# end
|
||||
#
|
||||
# it 'has a name for the target entry' do
|
||||
# @page.target_entry_name.should == 'foo'
|
||||
# end
|
||||
#
|
||||
# it 'uses the find_by_permalink method when fetching the entry' do
|
||||
# Foo.expects(:find_by_permalink)
|
||||
# @page.fetch_target_entry('foo')
|
||||
# end
|
||||
#
|
||||
# context '#descendants' do
|
||||
#
|
||||
# before(:each) do
|
||||
# @home = FactoryGirl.create(:page)
|
||||
# @page.attributes = { :parent_id => @home._id, :site => @home.site }; @page.save!
|
||||
# @sub_page = FactoryGirl.build(:page, :title => 'Subpage', :slug => 'foo', :parent => @page, :site => @home.site, :templatized => false)
|
||||
# end
|
||||
#
|
||||
# it 'inherits the templatized property from its parent' do
|
||||
# @sub_page.valid?
|
||||
# @sub_page.templatized?.should be_true
|
||||
# @sub_page.templatized_from_parent?.should be_true
|
||||
# @sub_page.target_klass_name.should == 'Foo'
|
||||
# end
|
||||
#
|
||||
# it 'gets templatized if its parent is' do
|
||||
# @page.attributes = { :templatized => false, :target_klass_name => nil }; @page.save!
|
||||
# @sub_page.save.should be_true
|
||||
# @sub_page.templatized?.should be_false
|
||||
#
|
||||
# @page.attributes = { :templatized => true, :target_klass_name => 'Foo' }; @page.save!
|
||||
# @sub_page.reload
|
||||
# @sub_page.templatized?.should be_true
|
||||
# @sub_page.templatized_from_parent?.should be_true
|
||||
# @sub_page.target_klass_name.should == 'Foo'
|
||||
# end
|
||||
#
|
||||
# it 'is not templatized if its parent is no more a templatized page' do
|
||||
# @sub_page.save.should be_true
|
||||
# @page.templatized = false; @page.save!
|
||||
# @sub_page.reload
|
||||
# @sub_page.templatized.should be_false
|
||||
# @sub_page.templatized_from_parent.should be_false
|
||||
# @sub_page.target_klass_name.should be_nil
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# context 'using a content type' do
|
||||
#
|
||||
# before(:each) do
|
||||
# @site = FactoryGirl.build(:site)
|
||||
# @content_type = FactoryGirl.build(:content_type, :slug => 'posts', :site => @site)
|
||||
# @page.site = @site
|
||||
# @page.target_klass_name = 'Locomotive::Entry42'
|
||||
# end
|
||||
#
|
||||
# it 'has a name for the target entry' do
|
||||
# @site.stubs(:content_types).returns(mock(:find => @content_type))
|
||||
# @page.target_entry_name.should == 'post'
|
||||
# end
|
||||
#
|
||||
# context '#security' do
|
||||
#
|
||||
# before(:each) do
|
||||
# Locomotive::ContentType.stubs(:find).returns(@content_type)
|
||||
# end
|
||||
#
|
||||
# it 'is valid if the content type belongs to the site' do
|
||||
# @page.send(:ensure_target_klass_name_security)
|
||||
# @page.errors.should be_empty
|
||||
# end
|
||||
#
|
||||
# it 'does not valid the page if the content type does not belong to the site' do
|
||||
# @content_type.site = FactoryGirl.build(:site)
|
||||
# @page.send(:ensure_target_klass_name_security)
|
||||
# @page.errors[:target_klass_name].should == ['presents a security problem']
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# end
|
||||
#
|
||||
# end
|
||||
|
||||
describe 'listed extension' do
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user