Merge remote-tracking branch 'origin/2.0.0.rc' into 2.0.0.rc
This commit is contained in:
commit
114218b8c4
102
Gemfile.lock
102
Gemfile.lock
@ -17,18 +17,18 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/locomotivecms/custom_fields.git
|
||||
revision: e54c3ddfce0e24668d02c372c6143a722718e215
|
||||
revision: 5b0e68859eaca41ac9d7a0231c6cd68ad66018b8
|
||||
branch: 2.0.0.rc
|
||||
specs:
|
||||
custom_fields (2.0.0.rc8)
|
||||
custom_fields (2.0.0.rc9)
|
||||
activesupport (~> 3.2.1)
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
mongoid (~> 2.4.5)
|
||||
mongoid (~> 2.4.7)
|
||||
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
locomotive_cms (2.0.0.rc2)
|
||||
locomotive_cms (2.0.0.rc3)
|
||||
RedCloth (~> 4.2.8)
|
||||
actionmailer-with-request (~> 0.3.0)
|
||||
bson_ext (~> 1.5.2)
|
||||
@ -36,7 +36,7 @@ PATH
|
||||
carrierwave-mongoid (~> 0.1.3)
|
||||
cells (~> 3.8.0)
|
||||
codemirror-rails (~> 2.21)
|
||||
custom_fields (~> 2.0.0.rc8)
|
||||
custom_fields (~> 2.0.0.rc9)
|
||||
devise (~> 1.5.3)
|
||||
dragonfly (~> 0.9.8)
|
||||
flash_cookie_session (~> 1.1.1)
|
||||
@ -66,14 +66,14 @@ GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
RedCloth (4.2.9)
|
||||
actionmailer (3.2.1)
|
||||
actionpack (= 3.2.1)
|
||||
actionmailer (3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
mail (~> 2.4.0)
|
||||
actionmailer-with-request (0.3.0)
|
||||
rails (>= 3)
|
||||
actionpack (3.2.1)
|
||||
activemodel (= 3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
actionpack (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.1)
|
||||
@ -81,18 +81,18 @@ GEM
|
||||
rack-cache (~> 1.1)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.1.2)
|
||||
activemodel (3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
activemodel (3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.1)
|
||||
activemodel (= 3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
arel (~> 3.0.0)
|
||||
activerecord (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.1)
|
||||
activemodel (= 3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
activesupport (3.2.1)
|
||||
activeresource (3.2.2)
|
||||
activemodel (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
activesupport (3.2.2)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
addressable (2.2.7)
|
||||
@ -112,10 +112,10 @@ GEM
|
||||
xpath (~> 0.1.4)
|
||||
carrierwave (0.5.8)
|
||||
activesupport (~> 3.0)
|
||||
carrierwave-mongoid (0.1.3)
|
||||
carrierwave (>= 0.5.6)
|
||||
carrierwave-mongoid (0.1.4)
|
||||
carrierwave (~> 0.5.6)
|
||||
mongoid (~> 2.1)
|
||||
cells (3.8.2)
|
||||
cells (3.8.3)
|
||||
actionpack (~> 3.0)
|
||||
railties (~> 3.0)
|
||||
childprocess (0.3.1)
|
||||
@ -140,7 +140,7 @@ GEM
|
||||
capybara (>= 1.1.2)
|
||||
cucumber (>= 1.1.8)
|
||||
nokogiri (>= 1.5.0)
|
||||
database_cleaner (0.7.1)
|
||||
database_cleaner (0.7.2)
|
||||
devise (1.5.3)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.0.3)
|
||||
@ -175,7 +175,7 @@ GEM
|
||||
formtastic (2.0.2)
|
||||
rails (~> 3.0)
|
||||
fssm (0.2.8.1)
|
||||
gherkin (2.9.0)
|
||||
gherkin (2.9.3)
|
||||
json (>= 1.4.6)
|
||||
haml (3.1.4)
|
||||
highline (1.6.11)
|
||||
@ -188,13 +188,13 @@ GEM
|
||||
jquery-rails (1.0.19)
|
||||
railties (~> 3.0)
|
||||
thor (~> 0.14)
|
||||
json (1.6.5)
|
||||
json (1.6.6)
|
||||
kaminari (0.13.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
kgio (2.7.2)
|
||||
launchy (2.0.5)
|
||||
kgio (2.7.4)
|
||||
launchy (2.1.0)
|
||||
addressable (~> 2.2.6)
|
||||
locomotive-aloha-rails (0.20.1.1)
|
||||
actionpack (~> 3.2.1)
|
||||
@ -203,16 +203,16 @@ GEM
|
||||
locomotive-tinymce-rails (3.4.7.1)
|
||||
actionpack (~> 3.2.1)
|
||||
locomotive_liquid (2.2.2)
|
||||
mail (2.4.1)
|
||||
mail (2.4.4)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.17.2)
|
||||
mime-types (1.18)
|
||||
mimetype-fu (0.1.2)
|
||||
mocha (0.9.12)
|
||||
mongo (1.5.2)
|
||||
bson (= 1.5.2)
|
||||
mongoid (2.4.6)
|
||||
mongoid (2.4.7)
|
||||
activemodel (~> 3.1)
|
||||
mongo (~> 1.3)
|
||||
tzinfo (~> 0.3.22)
|
||||
@ -221,34 +221,34 @@ GEM
|
||||
net-scp (1.0.4)
|
||||
net-ssh (>= 1.99.1)
|
||||
net-ssh (2.3.0)
|
||||
nokogiri (1.5.0)
|
||||
orm_adapter (0.0.6)
|
||||
nokogiri (1.5.2)
|
||||
orm_adapter (0.0.7)
|
||||
pickle (0.4.10)
|
||||
cucumber (>= 0.8)
|
||||
rake
|
||||
polyglot (0.3.3)
|
||||
rack (1.4.1)
|
||||
rack-cache (1.1)
|
||||
rack-cache (1.2)
|
||||
rack (>= 0.4)
|
||||
rack-ssl (1.3.2)
|
||||
rack
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.1)
|
||||
actionmailer (= 3.2.1)
|
||||
actionpack (= 3.2.1)
|
||||
activerecord (= 3.2.1)
|
||||
activeresource (= 3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
rails (3.2.2)
|
||||
actionmailer (= 3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
activerecord (= 3.2.2)
|
||||
activeresource (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.1)
|
||||
railties (= 3.2.2)
|
||||
rails-backbone (0.6.1)
|
||||
coffee-script (~> 2.2.0)
|
||||
ejs (~> 1.0.0)
|
||||
railties (>= 3.1.0)
|
||||
railties (3.2.1)
|
||||
actionpack (= 3.2.1)
|
||||
activesupport (= 3.2.1)
|
||||
railties (3.2.2)
|
||||
actionpack (= 3.2.2)
|
||||
activesupport (= 3.2.2)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
@ -281,14 +281,14 @@ GEM
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.1.15)
|
||||
sass-rails (3.2.4)
|
||||
sass-rails (3.2.5)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
selenium-webdriver (2.19.0)
|
||||
selenium-webdriver (2.20.0)
|
||||
childprocess (>= 0.2.5)
|
||||
ffi (~> 1.0.9)
|
||||
multi_json (~> 1.0.4)
|
||||
ffi (~> 1.0)
|
||||
multi_json (~> 1.0)
|
||||
rubyzip
|
||||
shoulda-matchers (1.0.0)
|
||||
sprockets (2.1.2)
|
||||
@ -301,11 +301,11 @@ GEM
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.31)
|
||||
uglifier (1.2.3)
|
||||
tzinfo (0.3.32)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
unicorn (4.2.0)
|
||||
unicorn (4.2.1)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
|
@ -73,18 +73,20 @@ class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.F
|
||||
new_entry = new Locomotive.Models.ContentEntry(@options["#{name}_new_entry"])
|
||||
view = new Locomotive.Views.Shared.Fields.HasManyView model: @model, name: name, new_entry: new_entry, inverse_of: inverse_of
|
||||
|
||||
@_has_many_field_views.push(view)
|
||||
if view.ui_enabled()
|
||||
@_has_many_field_views.push(view)
|
||||
|
||||
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
|
||||
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
|
||||
|
||||
enable_many_to_many_fields: ->
|
||||
_.each @model.get('many_to_many_custom_fields'), (field) =>
|
||||
name = field[0]
|
||||
view = new Locomotive.Views.Shared.Fields.ManyToManyView model: @model, name: name, all_entries: @options["all_#{name}_entries"]
|
||||
|
||||
@_many_to_many_field_views.push(view)
|
||||
if view.ui_enabled()
|
||||
@_many_to_many_field_views.push(view)
|
||||
|
||||
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
|
||||
@$("##{@model.paramRoot}_#{name}_input label").after(view.render().el)
|
||||
|
||||
slugify_label_field: ->
|
||||
@$('li.input.highlighted > input[type=text]').slugify(target: @$('#content_entry__slug'))
|
||||
|
@ -112,6 +112,11 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
|
||||
data: { parent_id: @$('#page_parent_id').val(), slug: @$('#page_slug').val() }
|
||||
success: (data) =>
|
||||
@$('#page_slug_input .inline-hints').html(data.url).effect('highlight')
|
||||
if data.templatized_parent
|
||||
@$('li#page_slug_input').show()
|
||||
@$('li#page_templatized_input, li#page_target_klass_name_input').hide()
|
||||
else
|
||||
@$('li#page_templatized_input, li#page_target_klass_name_input').show()
|
||||
|
||||
enable_response_type_select: ->
|
||||
@$('li#page_response_type_input').change (event) =>
|
||||
@ -129,6 +134,8 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
|
||||
off_callback: =>
|
||||
@$('li#page_target_klass_name_input').hide()
|
||||
|
||||
@$('li#page_templatized_input').hide() if @model.get('templatized_from_parent') == true
|
||||
|
||||
enable_redirect_checkbox: ->
|
||||
@_enable_checkbox 'redirect',
|
||||
features: ['templatized', 'cache_strategy']
|
||||
|
@ -34,6 +34,9 @@ class Locomotive.Views.Shared.Fields.HasManyView extends Backbone.View
|
||||
|
||||
return @
|
||||
|
||||
ui_enabled: ->
|
||||
@template()?
|
||||
|
||||
insert_entries: ->
|
||||
if @collection.length > 0
|
||||
@collection.each (entry) => @insert_entry(entry)
|
||||
|
@ -39,6 +39,9 @@ class Locomotive.Views.Shared.Fields.ManyToManyView extends Backbone.View
|
||||
|
||||
return @
|
||||
|
||||
ui_enabled: ->
|
||||
@template()?
|
||||
|
||||
insert_entries: ->
|
||||
if @collection.length > 0
|
||||
@collection.each (entry) => @insert_entry(entry)
|
||||
|
@ -11,6 +11,7 @@ body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,9 +53,10 @@ module Locomotive
|
||||
end
|
||||
|
||||
def get_path
|
||||
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].permalink)
|
||||
page.send(:build_fullpath)
|
||||
render :json => { :url => public_page_url(page), :slug => page.slug }
|
||||
page = current_site.pages.build(:parent => current_site.pages.find(params[:parent_id]), :slug => params[:slug].permalink).tap do |p|
|
||||
p.valid?; p.send(:build_fullpath)
|
||||
end
|
||||
render :json => { :url => public_page_url(page), :slug => page.slug, :templatized_parent => page.templatized_from_parent? }
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -7,6 +7,7 @@ module Locomotive
|
||||
|
||||
included do
|
||||
|
||||
## fields ##
|
||||
field :listed, :type => Boolean, :default => true
|
||||
|
||||
end
|
||||
|
@ -6,17 +6,22 @@ module Locomotive
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
## fields ##
|
||||
field :serialized_template, :type => Binary, :localize => true
|
||||
field :template_dependencies, :type => Array, :default => [], :localize => true
|
||||
field :snippet_dependencies, :type => Array, :default => [], :localize => true
|
||||
|
||||
## virtual attributes
|
||||
attr_reader :template_changed
|
||||
|
||||
## callbacks ##
|
||||
before_validation :serialize_template
|
||||
after_save :update_template_descendants
|
||||
|
||||
## validations ##
|
||||
validate :template_must_be_valid
|
||||
|
||||
## scopes ##
|
||||
scope :pages, lambda { |domain| { :any_in => { :domains => [*domain] } } }
|
||||
end
|
||||
|
||||
|
@ -3,10 +3,90 @@ module Locomotive
|
||||
module Page
|
||||
module Render
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def render(context)
|
||||
self.template.render(context)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
# Given both a site and a path, this method tries
|
||||
# to get the matching page.
|
||||
# If the page is templatized, the related content entry is
|
||||
# associated to the page (page.content_entry stores the entry).
|
||||
# If no page is found, then it returns the 404 one instead.
|
||||
#
|
||||
# @param [ Site ] site The site where to find the page
|
||||
# @param [ String ] path The fullpath got from the request
|
||||
# @param [ Boolean ] logged_in True if someone is logged in Locomotive
|
||||
#
|
||||
# @return [ Page ] The page matching the criteria OR the 404 one if none
|
||||
#
|
||||
def fetch_page_from_path(site, path, logged_in)
|
||||
page = nil
|
||||
depth = path == 'index' ? 0 : path.split('/').size
|
||||
|
||||
matching_paths = path == 'index' ? %w(index) : path_combinations(path)
|
||||
|
||||
site.pages.where(:depth => depth, :fullpath.in => matching_paths).each do |_page|
|
||||
if !_page.published? && !logged_in
|
||||
next
|
||||
else
|
||||
if _page.templatized?
|
||||
%r(^#{_page.fullpath.gsub('content_type_template', '([^\/]+)')}$) =~ path
|
||||
|
||||
permalink = $1
|
||||
|
||||
_page.content_entry = _page.fetch_target_entry(permalink)
|
||||
|
||||
if _page.content_entry.nil? || (!_page.content_entry.visible? && !logged_in) # content instance not found or not visible
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page = _page
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
page || site.pages.not_found.published.first
|
||||
end
|
||||
|
||||
# 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)
|
||||
#
|
||||
# @param [ String ] path The path to the page
|
||||
#
|
||||
# @return [ Array ] An array of all the combinations
|
||||
#
|
||||
def path_combinations(path)
|
||||
_path_combinations(path.split('/'))
|
||||
end
|
||||
|
||||
#:nodoc:
|
||||
def _path_combinations(segments, can_include_template = true)
|
||||
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'))
|
||||
[*_combinations].map do |_combination|
|
||||
File.join(_segment, _combination)
|
||||
end
|
||||
else
|
||||
[_segment]
|
||||
end
|
||||
end.flatten
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -7,7 +7,9 @@ module Locomotive
|
||||
|
||||
included do
|
||||
|
||||
field :templatized, :type => Boolean, :default => false
|
||||
## fields ##
|
||||
field :templatized, :type => Boolean, :default => false
|
||||
field :templatized_from_parent, :type => Boolean, :default => false
|
||||
field :target_klass_name
|
||||
|
||||
## validations ##
|
||||
@ -15,11 +17,16 @@ module Locomotive
|
||||
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
|
||||
@ -70,10 +77,26 @@ module Locomotive
|
||||
|
||||
protected
|
||||
|
||||
def set_slug_if_templatized
|
||||
self.slug = 'content_type_template' if self.templatized?
|
||||
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?
|
||||
|
||||
@ -86,7 +109,25 @@ module Locomotive
|
||||
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
|
||||
|
@ -38,6 +38,10 @@ module Locomotive
|
||||
Page.quick_tree(self)
|
||||
end
|
||||
|
||||
def fetch_page(path, logged_in)
|
||||
Locomotive::Page.fetch_page_from_path self, path, logged_in
|
||||
end
|
||||
|
||||
def accounts
|
||||
Account.criteria.in(:_id => self.memberships.map(&:account_id))
|
||||
end
|
||||
|
@ -43,7 +43,7 @@ module Locomotive
|
||||
hash[meth]= (if self.source.custom_fields_methods.include?(meth.to_s)
|
||||
if self.source.is_a_custom_field_many_relationship?(meth.to_s)
|
||||
# go deeper
|
||||
self.source.send(meth).map { |entry| entry.to_presenter(:depth => self.depth + 1) }
|
||||
self.source.send(meth).ordered.map { |entry| entry.to_presenter(:depth => self.depth + 1) }
|
||||
else
|
||||
self.source.send(meth) rescue nil
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Locomotive
|
||||
class PagePresenter < BasePresenter
|
||||
|
||||
delegate :title, :slug, :fullpath, :handle, :raw_template, :published, :listed, :templatized, :redirect, :redirect_url, :template_changed, :cache_strategy, :response_type, :to => :source
|
||||
delegate :title, :slug, :fullpath, :handle, :raw_template, :published, :listed, :templatized, :templatized_from_parent, :redirect, :redirect_url, :template_changed, :cache_strategy, :response_type, :to => :source
|
||||
|
||||
def escaped_raw_template
|
||||
h(self.source.raw_template)
|
||||
@ -12,7 +12,7 @@ module Locomotive
|
||||
end
|
||||
|
||||
def included_methods
|
||||
super + %w(title slug fullpath handle raw_template published listed templatized redirect redirect_url cache_strategy response_type template_changed editable_elements localized_fullpaths)
|
||||
super + %w(title slug fullpath handle raw_template published listed templatized templatized_from_parent redirect redirect_url cache_strategy response_type template_changed editable_elements localized_fullpaths)
|
||||
end
|
||||
|
||||
def localized_fullpaths
|
||||
|
@ -16,7 +16,7 @@
|
||||
- if not @page.index? and not @page.not_found?
|
||||
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
|
||||
|
||||
= f.input :slug, :required => false, :hint => @page.slug.blank? ? t('.empty_slug') : public_page_url(@page), :input_html => { :'data-url' => get_path_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?};", :class => 'em-inline-hints' }
|
||||
= f.input :slug, :required => false, :hint => @page.slug.blank? ? t('.empty_slug') : public_page_url(@page), :input_html => { :'data-url' => get_path_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized? && !@page.templatized_from_parent?};", :class => 'em-inline-hints' }
|
||||
|
||||
= f.inputs :name => :seo, :class => "inputs foldable #{'folded' if inputs_folded?(@page)}" do
|
||||
|
||||
@ -34,9 +34,9 @@
|
||||
|
||||
= f.input :response_type, :as => :select, :collection => options_for_page_response_type, :include_blank => false
|
||||
|
||||
= f.input :templatized, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.redirect?}"
|
||||
= f.input :templatized, :as => :'Locomotive::Toggle', :style => "#{'display: none' if @page.redirect? || @page.templatized_from_parent?}"
|
||||
|
||||
= 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 :target_klass_name, :as => :select, :collection => options_for_target_klass_name, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized? && !@page.templatized_from_parent?}" }
|
||||
|
||||
= f.input :published, :as => :'Locomotive::Toggle'
|
||||
|
||||
|
@ -289,3 +289,18 @@ fr:
|
||||
explanations: "Si vous avez déjà uploadé le template de site par défaut (voir instructions), vous pouvez l'utiliser dès maintenant. Ou vous pouvez uploader un template de site sous forme d'un fichier zip (quelques themes disponibles <a href=\"http://www.locomotivecms.com/support/themes\">ici</a>)."
|
||||
back_to_default_template: "Cliquez <a href='#'>ici</a> pour sélectionner à la place le template de site par défault"
|
||||
next: Créer site
|
||||
|
||||
public:
|
||||
pages:
|
||||
show_toolbar:
|
||||
statuses:
|
||||
loading: "Chargement...."
|
||||
disabled: "Editeur en ligne désactivé"
|
||||
labels:
|
||||
save_changes: "Enregistrez les modifications: "
|
||||
editing_mode: "Mode édition: "
|
||||
lang: "Langue: "
|
||||
buttons:
|
||||
back: "Revenir au panneau d'administration"
|
||||
confirm: "Valider"
|
||||
cancel: "Annuler"
|
||||
|
52
features/public/many_to_many.feature
Normal file
52
features/public/many_to_many.feature
Normal file
@ -0,0 +1,52 @@
|
||||
Feature: Many to Many Association
|
||||
As a designer
|
||||
In order to make dealing with models easier
|
||||
I want to be able to display other models that have a many to many association
|
||||
|
||||
Background:
|
||||
Given I have the site: "test site" set up
|
||||
And I have a custom model named "Articles" with
|
||||
| label | type | required |
|
||||
| Title | string | true |
|
||||
| Body | string | false |
|
||||
And I have a custom model named "Projects" with
|
||||
| label | type | required | target |
|
||||
| Name | string | true | |
|
||||
| Description | text | false | |
|
||||
And I set up a many_to_many relationship between "Articles" and "Projects"
|
||||
And I have entries for "Articles" with
|
||||
| title | body |
|
||||
| Hello world | Lorem ipsum |
|
||||
| Lorem ipsum | Lorem ipsum... |
|
||||
And I have entries for "Projects" with
|
||||
| name | description |
|
||||
| My sexy project | Lorem ipsum |
|
||||
| Foo project | Lorem ipsum... |
|
||||
| Bar project | Lorem ipsum... |
|
||||
| Baz project | Lorem ipsum... |
|
||||
And I attach the "My sexy project" project to the "Hello world" article
|
||||
And I attach the "Baz project" project to the "Hello world" article
|
||||
And I attach the "Foo project" project to the "Hello world" article
|
||||
|
||||
Scenario: Displaying the entries of a many to many association
|
||||
Given a page named "article-projects" with the template:
|
||||
"""
|
||||
{% assign article = contents.articles.first %}
|
||||
<h1>Projects for {{ article.title }}</h1>
|
||||
<ul>
|
||||
{% for project in article.projects %}<li>{{ project.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
"""
|
||||
When I view the rendered page at "/article-projects"
|
||||
Then the rendered output should look like:
|
||||
"""
|
||||
|
||||
<h1>Projects for Hello world</h1>
|
||||
<ul>
|
||||
<li>My sexy project</li>
|
||||
<li>Baz project</li>
|
||||
<li>Foo project</li>
|
||||
|
||||
</ul>
|
||||
"""
|
@ -18,7 +18,7 @@ Then /^I should be able to display paginated models$/ do
|
||||
{{ paginate | default_pagination }}
|
||||
{% endpaginate %}
|
||||
}
|
||||
FactoryGirl.create(:page, :site => @site, :slug => 'hello', :raw_template => raw_template)
|
||||
FactoryGirl.create(:page, :site => @site, :slug => 'hello', :parent => @site.pages.root.first, :raw_template => raw_template)
|
||||
|
||||
# The page should have the first two articles
|
||||
visit '/hello'
|
||||
|
@ -41,7 +41,7 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$}
|
||||
:label => last_name,
|
||||
:type => 'many_to_many',
|
||||
:class_name => last_model.klass_with_custom_fields(:entries).to_s,
|
||||
:inverse_of => first_name.singularize.downcase
|
||||
:inverse_of => first_name.pluralize.downcase
|
||||
})
|
||||
|
||||
first_model.save
|
||||
@ -50,12 +50,22 @@ Given %r{^I set up a many_to_many relationship between "([^"]*)" and "([^"]*)"$}
|
||||
:label => first_name,
|
||||
:type => 'many_to_many',
|
||||
:class_name => first_model.klass_with_custom_fields(:entries).to_s,
|
||||
:inverse_of => last_name.singularize.downcase
|
||||
:inverse_of => last_name.pluralize.downcase
|
||||
})
|
||||
|
||||
last_model.save
|
||||
end
|
||||
|
||||
Given %r{^I attach the "([^"]*)" ([\S]*) to the "([^"]*)" ([\S]*)$} do |target_name, target_model_name, souce_name, source_model_name|
|
||||
target_model = @site.content_types.where(:name => target_model_name.pluralize.capitalize).first
|
||||
source_model = @site.content_types.where(:name => source_model_name.pluralize.capitalize).first
|
||||
|
||||
target_entry = target_model.entries.where(:_slug => target_name.permalink).first
|
||||
source_entry = source_model.entries.where(:_slug => souce_name.permalink).first
|
||||
|
||||
source_entry.send(target_model_name.pluralize.downcase.parameterize('_').to_sym).push(target_entry)
|
||||
end
|
||||
|
||||
Then /^I should be able to view a paginated list of a has many association$/ do
|
||||
# Create models
|
||||
step %{I have an "Articles" model which has many "Comments"}
|
||||
@ -80,7 +90,7 @@ Then /^I should be able to view a paginated list of a has many association$/ do
|
||||
}
|
||||
|
||||
# Create a page
|
||||
FactoryGirl.create(:page, :site => @site, :slug => 'hello', :raw_template => raw_template)
|
||||
FactoryGirl.create(:page, :site => @site, :slug => 'hello', :parent => @site.pages.root.first, :raw_template => raw_template)
|
||||
|
||||
# The page should have the first two comments
|
||||
visit '/hello'
|
||||
|
@ -18,7 +18,7 @@ module Locomotive
|
||||
::ActionController::Base.wrap_parameters :format => [:json]
|
||||
end
|
||||
|
||||
initializer "Locomotive precompile hook" do |app|
|
||||
initializer "Locomotive precompile hook", :group => :all do |app|
|
||||
app.config.assets.precompile += %w(locomotive.js locomotive.css locomotive/inline_editor.js locomotive/inline_editor.css
|
||||
locomotive/not_logged_in.js locomotive/not_logged_in.css
|
||||
locomotive/aloha.js)
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'locomotive/liquid/drops/base'
|
||||
require 'locomotive/liquid/drops/proxy_collection'
|
||||
require 'locomotive/liquid/filters/base'
|
||||
|
||||
%w{. tags drops filters}.each do |dir|
|
||||
Dir[File.join(File.dirname(__FILE__), 'liquid', dir, '*.rb')].each { |lib| require lib }
|
||||
|
@ -45,7 +45,7 @@ module Locomotive
|
||||
if not @@forbidden_attributes.include?(meth.to_s)
|
||||
value = self._source.send(meth)
|
||||
|
||||
if value.respond_to?(:all)
|
||||
if value.respond_to?(:all) # check for an association
|
||||
filter_and_order_list(value)
|
||||
else
|
||||
value
|
||||
@ -70,7 +70,7 @@ module Locomotive
|
||||
end
|
||||
else
|
||||
list.ordered
|
||||
end.all
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
47
lib/locomotive/liquid/filters/base.rb
Normal file
47
lib/locomotive/liquid/filters/base.rb
Normal file
@ -0,0 +1,47 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
module Filters
|
||||
module Base
|
||||
|
||||
protected
|
||||
|
||||
# Convert an array of properties ('key:value') into a hash
|
||||
# Ex: ['width:50', 'height:100'] => { :width => '50', :height => '100' }
|
||||
def args_to_options(*args)
|
||||
options = {}
|
||||
args.flatten.each do |a|
|
||||
if (a =~ /^(.*):(.*)$/)
|
||||
options[$1.to_sym] = $2
|
||||
end
|
||||
end
|
||||
options
|
||||
end
|
||||
|
||||
# Write options (Hash) into a string according to the following pattern:
|
||||
# <key1>="<value1>", <key2>="<value2", ...etc
|
||||
def inline_options(options = {})
|
||||
return '' if options.empty?
|
||||
(options.stringify_keys.sort.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' '
|
||||
end
|
||||
|
||||
# Get the url to be used in html tags such as image_tag, flash_tag, ...etc
|
||||
# input: url (String) OR asset drop
|
||||
def get_url_from_asset(input)
|
||||
input.respond_to?(:url) ? input.url : input
|
||||
end
|
||||
|
||||
def asset_url(path)
|
||||
ThemeAssetUploader.url_for(@context.registers[:site], path)
|
||||
end
|
||||
|
||||
def absolute_url(url)
|
||||
url.starts_with?('/') ? url : "/#{url}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_filter(Base)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -6,7 +6,7 @@ module Locomotive
|
||||
# Returns a link tag that browsers and news readers can use to auto-detect an RSS or ATOM feed.
|
||||
# input: url of the feed
|
||||
# example:
|
||||
# {{ '/foo/bar' | auto_discovery_link_tag: 'rel:alternate', 'type:atom', 'title:A title' }}
|
||||
# {{ '/foo/bar' | auto_discovery_link_tag: 'rel:alternate', 'type:application/atom+xml', 'title:A title' }}
|
||||
def auto_discovery_link_tag(input, *args)
|
||||
options = args_to_options(args)
|
||||
|
||||
@ -17,7 +17,7 @@ module Locomotive
|
||||
%{<link rel="#{rel}" type="#{type}" title="#{title}" href="#{input}" />}
|
||||
end
|
||||
|
||||
# Write the url to a stylesheet resource
|
||||
# Write the url of a theme stylesheet
|
||||
# input: name of the css file
|
||||
def stylesheet_url(input)
|
||||
return '' if input.nil?
|
||||
@ -31,7 +31,7 @@ module Locomotive
|
||||
input
|
||||
end
|
||||
|
||||
# Write the link to a stylesheet resource
|
||||
# Write the link tag of a theme stylesheet
|
||||
# input: url of the css file
|
||||
def stylesheet_tag(input, media = 'screen')
|
||||
return '' if input.nil?
|
||||
@ -106,80 +106,6 @@ module Locomotive
|
||||
}.gsub(/ >/, '>').strip
|
||||
end
|
||||
|
||||
# Render the navigation for a paginated collection
|
||||
def default_pagination(paginate, *args)
|
||||
return '' if paginate['parts'].empty?
|
||||
|
||||
options = args_to_options(args)
|
||||
|
||||
previous_label = options[:previous_label] || I18n.t('pagination.previous')
|
||||
next_label = options[:next_label] || I18n.t('pagination.next')
|
||||
|
||||
previous_link = (if paginate['previous'].blank?
|
||||
"<span class=\"disabled prev_page\">#{previous_label}</span>"
|
||||
else
|
||||
"<a href=\"#{absolute_url(paginate['previous']['url'])}\" class=\"prev_page\">#{previous_label}</a>"
|
||||
end)
|
||||
|
||||
links = ""
|
||||
paginate['parts'].each do |part|
|
||||
links << (if part['is_link']
|
||||
"<a href=\"#{absolute_url(part['url'])}\">#{part['title']}</a>"
|
||||
elsif part['hellip_break']
|
||||
"<span class=\"gap\">#{part['title']}</span>"
|
||||
else
|
||||
"<span class=\"current\">#{part['title']}</span>"
|
||||
end)
|
||||
end
|
||||
|
||||
next_link = (if paginate['next'].blank?
|
||||
"<span class=\"disabled next_page\">#{next_label}</span>"
|
||||
else
|
||||
"<a href=\"#{absolute_url(paginate['next']['url'])}\" class=\"next_page\">#{next_label}</a>"
|
||||
end)
|
||||
|
||||
%{<div class="pagination #{options[:css]}">
|
||||
#{previous_link}
|
||||
#{links}
|
||||
#{next_link}
|
||||
</div>}
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Convert an array of properties ('key:value') into a hash
|
||||
# Ex: ['width:50', 'height:100'] => { :width => '50', :height => '100' }
|
||||
def args_to_options(*args)
|
||||
options = {}
|
||||
args.flatten.each do |a|
|
||||
if (a =~ /^(.*):(.*)$/)
|
||||
options[$1.to_sym] = $2
|
||||
end
|
||||
end
|
||||
options
|
||||
end
|
||||
|
||||
# Write options (Hash) into a string according to the following pattern:
|
||||
# <key1>="<value1>", <key2>="<value2", ...etc
|
||||
def inline_options(options = {})
|
||||
return '' if options.empty?
|
||||
(options.stringify_keys.sort.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ') << ' '
|
||||
end
|
||||
|
||||
# Get the url to be used in html tags such as image_tag, flash_tag, ...etc
|
||||
# input: url (String) OR asset drop
|
||||
def get_url_from_asset(input)
|
||||
input.respond_to?(:url) ? input.url : input
|
||||
end
|
||||
|
||||
def asset_url(path)
|
||||
ThemeAssetUploader.url_for(@context.registers[:site], path)
|
||||
end
|
||||
|
||||
def absolute_url(url)
|
||||
url.starts_with?('/') ? url : "/#{url}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_filter(Html)
|
||||
|
@ -3,24 +3,6 @@ module Locomotive
|
||||
module Filters
|
||||
module Misc
|
||||
|
||||
def underscore(input)
|
||||
input.to_s.gsub(' ', '_').gsub('/', '_').underscore
|
||||
end
|
||||
|
||||
def dasherize(input)
|
||||
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 }
|
||||
result
|
||||
end
|
||||
|
||||
def modulo(word, index, modulo)
|
||||
(index.to_i + 1) % modulo == 0 ? word : ''
|
||||
end
|
||||
@ -33,6 +15,49 @@ module Locomotive
|
||||
input.last
|
||||
end
|
||||
|
||||
def default(input, value)
|
||||
input.blank? ? value : input
|
||||
end
|
||||
|
||||
# Render the navigation for a paginated collection
|
||||
def default_pagination(paginate, *args)
|
||||
return '' if paginate['parts'].empty?
|
||||
|
||||
options = args_to_options(args)
|
||||
|
||||
previous_label = options[:previous_label] || I18n.t('pagination.previous')
|
||||
next_label = options[:next_label] || I18n.t('pagination.next')
|
||||
|
||||
previous_link = (if paginate['previous'].blank?
|
||||
"<span class=\"disabled prev_page\">#{previous_label}</span>"
|
||||
else
|
||||
"<a href=\"#{absolute_url(paginate['previous']['url'])}\" class=\"prev_page\">#{previous_label}</a>"
|
||||
end)
|
||||
|
||||
links = ""
|
||||
paginate['parts'].each do |part|
|
||||
links << (if part['is_link']
|
||||
"<a href=\"#{absolute_url(part['url'])}\">#{part['title']}</a>"
|
||||
elsif part['hellip_break']
|
||||
"<span class=\"gap\">#{part['title']}</span>"
|
||||
else
|
||||
"<span class=\"current\">#{part['title']}</span>"
|
||||
end)
|
||||
end
|
||||
|
||||
next_link = (if paginate['next'].blank?
|
||||
"<span class=\"disabled next_page\">#{next_label}</span>"
|
||||
else
|
||||
"<a href=\"#{absolute_url(paginate['next']['url'])}\" class=\"next_page\">#{next_label}</a>"
|
||||
end)
|
||||
|
||||
%{<div class="pagination #{options[:css]}">
|
||||
#{previous_link}
|
||||
#{links}
|
||||
#{next_link}
|
||||
</div>}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_filter(Misc)
|
||||
|
@ -3,6 +3,24 @@ module Locomotive
|
||||
module Filters
|
||||
module Text
|
||||
|
||||
def underscore(input)
|
||||
input.to_s.gsub(' ', '_').gsub('/', '_').underscore
|
||||
end
|
||||
|
||||
def dasherize(input)
|
||||
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 }
|
||||
result
|
||||
end
|
||||
|
||||
def textile(input)
|
||||
::RedCloth.new(input).to_html
|
||||
end
|
||||
|
@ -1,21 +0,0 @@
|
||||
module Locomotive
|
||||
module Liquid
|
||||
module Tags
|
||||
class Blueprint < ::Liquid::Tag
|
||||
|
||||
def render(context)
|
||||
%{
|
||||
<link href="/stylesheets/admin/blueprint/screen.css" media="screen, projection" rel="stylesheet" type="text/css" />
|
||||
<link href="/stylesheets/admin/blueprint/print.css" media="print" rel="stylesheet" type="text/css" />
|
||||
<!--[if IE]>
|
||||
<link href="/stylesheets/admin/blueprint/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
|
||||
<![endif]-->
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('blueprint_stylesheets', Blueprint)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,17 +0,0 @@
|
||||
module Liquid
|
||||
module Locomotive
|
||||
module Tags
|
||||
class Jquery < ::Liquid::Tag
|
||||
|
||||
def render(context)
|
||||
%{
|
||||
<script src="/javascripts/jquery.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/jquery.ui.js" type="text/javascript"></script>
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('jQuery', Jquery)
|
||||
end
|
||||
end
|
||||
end
|
@ -11,11 +11,11 @@ module Locomotive
|
||||
#
|
||||
# options:
|
||||
# - label: iso (de, fr, en, ...etc), locale (Deutsch, Français, English, ...etc), title (page title)
|
||||
# - sep: piece of html code seperating 2 locales
|
||||
# - sep: piece of html code separating 2 locales
|
||||
#
|
||||
# notes:
|
||||
# - "iso" is the default choice for label
|
||||
# - " | " is the default seperating code
|
||||
# - " | " is the default separating code
|
||||
#
|
||||
class LocaleSwitcher < ::Liquid::Tag
|
||||
|
||||
|
@ -46,7 +46,7 @@ module Locomotive
|
||||
end
|
||||
page_count, current_page = pagination['total_pages'], pagination['current_page']
|
||||
|
||||
path = context['path']
|
||||
path = sanitize_path(context['fullpath'])
|
||||
|
||||
pagination['previous'] = link(I18n.t('pagination.previous'), current_page - 1, path) if pagination['previous_page']
|
||||
pagination['next'] = link(I18n.t('pagination.next'), current_page + 1, path) if pagination['next_page']
|
||||
@ -83,6 +83,12 @@ module Locomotive
|
||||
|
||||
private
|
||||
|
||||
def sanitize_path(path)
|
||||
_path = path.gsub(/page=[0-9]+&?/, '').gsub(/_pjax=true&?/, '')
|
||||
_path = _path.slice(0..-2) if _path.last == '?' || _path.last == '&'
|
||||
_path
|
||||
end
|
||||
|
||||
def window_size
|
||||
3
|
||||
end
|
||||
@ -92,7 +98,8 @@ module Locomotive
|
||||
end
|
||||
|
||||
def link(title, page, path)
|
||||
{ 'title' => title, 'url' => path + "?page=#{page}", 'is_link' => true}
|
||||
_path = %(#{path}#{path.include?('?') ? '&' : '?'}page=#{page})
|
||||
{ 'title' => title, 'url' => _path, 'is_link' => true }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -16,7 +16,7 @@ module Locomotive
|
||||
onmouseover="this.style.backgroundPosition='0px -45px'"
|
||||
onmousedown="this.style.backgroundPosition='0px -90px'"
|
||||
onmouseup="this.style.backgroundPosition='0px 0px'"
|
||||
style="display: block;position:fixed;top: 10px; right: 10px;width: 48px; height: 45px;text-indent:-9999px;text-decoration:none;background: transparent url\('/assets/locomotive/icons/start.png'\) no-repeat 0 0;">
|
||||
style="display: block;z-index: 1031;position: fixed;top: 10px; right: 10px;width: 48px; height: 45px;text-indent:-9999px;text-decoration:none;background: transparent url\('/assets/locomotive/icons/start.png'\) no-repeat 0 0;">
|
||||
Admin</a>
|
||||
</body>
|
||||
)
|
||||
|
@ -26,28 +26,7 @@ module Locomotive
|
||||
end
|
||||
|
||||
def locomotive_page
|
||||
page = nil
|
||||
path = self.locomotive_page_path
|
||||
|
||||
current_site.pages.any_in(:fullpath => [*path]).each do |_page|
|
||||
if not _page.published? and current_locomotive_account.nil?
|
||||
next
|
||||
else
|
||||
if _page.templatized?
|
||||
@content_entry = _page.fetch_target_entry(File.basename(path.first))
|
||||
|
||||
if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible
|
||||
next
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page = _page
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
page || not_found_page
|
||||
current_site.fetch_page self.locomotive_page_path, current_locomotive_account.present?
|
||||
end
|
||||
|
||||
def locomotive_page_path
|
||||
@ -58,11 +37,6 @@ module Locomotive
|
||||
|
||||
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
|
||||
|
||||
path
|
||||
end
|
||||
|
||||
@ -75,6 +49,7 @@ module Locomotive
|
||||
'current_page' => self.params[:page],
|
||||
'params' => self.params,
|
||||
'path' => request.path,
|
||||
'fullpath' => request.fullpath,
|
||||
'url' => request.url,
|
||||
'now' => Time.now.utc,
|
||||
'today' => Date.today,
|
||||
@ -88,8 +63,8 @@ module Locomotive
|
||||
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
|
||||
assigns['entry'] = @page.content_entry
|
||||
assigns[@page.target_entry_name] = @page.content_entry # just here to help to write readable liquid code
|
||||
end
|
||||
|
||||
registers = {
|
||||
@ -120,10 +95,6 @@ module Locomotive
|
||||
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
|
||||
|
@ -1,3 +1,3 @@
|
||||
module Locomotive #:nodoc
|
||||
VERSION = '2.0.0.rc2'
|
||||
VERSION = '2.0.0.rc3'
|
||||
end
|
||||
|
@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency 'mongoid', '~> 2.4.5'
|
||||
s.add_dependency 'locomotive-mongoid-tree', '~> 0.6.2'
|
||||
|
||||
s.add_dependency 'custom_fields', '~> 2.0.0.rc8'
|
||||
s.add_dependency 'custom_fields', '~> 2.0.0.rc9'
|
||||
|
||||
s.add_dependency 'kaminari', '~> 0.13.0'
|
||||
|
||||
|
@ -13,7 +13,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do
|
||||
it 'loops through the list' do
|
||||
template = %({% for project in category.projects %}{{ project }},{% endfor %})
|
||||
|
||||
@list.expects(:ordered).returns(mock('criteria', :all => %w(a b)))
|
||||
@list.expects(:ordered).returns(%w(a b))
|
||||
|
||||
render(template, { 'category' => @category }).should == 'a,b,'
|
||||
end
|
||||
@ -21,7 +21,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do
|
||||
it 'filters the list' do
|
||||
template = %({% with_scope order_by: 'name ASC', active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
|
||||
|
||||
@list.expects(:order_by).with(['name', 'ASC']).returns(mock('criteria', :all => %w(a b)))
|
||||
@list.expects(:order_by).with(['name', 'ASC']).returns(%w(a b))
|
||||
@list.expects(:where).with({ 'active' => true }).returns(@list)
|
||||
|
||||
render(template, { 'category' => @category }).should == 'a,b,'
|
||||
@ -30,7 +30,7 @@ describe Locomotive::Liquid::Drops::ContentEntry do
|
||||
it 'filters the list and uses the default order' do
|
||||
template = %({% with_scope active: true %}{% for project in category.projects %}{{ project }},{% endfor %}{% endwith_scope %})
|
||||
|
||||
@list.expects(:ordered).returns(mock('criteria', :all => %w(a b)))
|
||||
@list.expects(:ordered).returns(%w(a b))
|
||||
@list.expects(:where).with({ 'active' => true }).returns(@list)
|
||||
|
||||
render(template, { 'category' => @category }).should == 'a,b,'
|
||||
|
@ -2,6 +2,7 @@ require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Filters::Html do
|
||||
|
||||
include Locomotive::Liquid::Filters::Base
|
||||
include Locomotive::Liquid::Filters::Html
|
||||
|
||||
before(:each) do
|
||||
@ -206,39 +207,6 @@ describe Locomotive::Liquid::Filters::Html do
|
||||
}.strip
|
||||
end
|
||||
|
||||
it 'should return a navigation block for the pagination' do
|
||||
pagination = {
|
||||
"previous" => nil,
|
||||
"parts" => [
|
||||
{ 'title' => '1', 'is_link' => false },
|
||||
{ 'title' => '2', 'is_link' => true, 'url' => '/?page=2' },
|
||||
{ 'title' => '…', 'is_link' => false, 'hellip_break' => true },
|
||||
{ 'title' => '5', 'is_link' => true, 'url' => '/?page=5' }
|
||||
],
|
||||
"next" => { 'title' => 'next', 'is_link' => true, 'url' => '/?page=2' }
|
||||
}
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should match(/<div class="pagination flickr_pagination">/)
|
||||
html.should match(/<span class="disabled prev_page">« Previous<\/span>/)
|
||||
html.should match(/<a href="\/\?page=2">2<\/a>/)
|
||||
html.should match(/<span class=\"gap\">\…<\/span>/)
|
||||
html.should match(/<a href="\/\?page=2" class="next_page">Next »<\/a>/)
|
||||
|
||||
pagination.merge!({
|
||||
'previous' => { 'title' => 'previous', 'is_link' => true, 'url' => '/?page=4' },
|
||||
'next' => nil
|
||||
})
|
||||
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should_not match(/<span class="disabled prev_page">« Previous<\/span>/)
|
||||
html.should match(/<a href="\/\?page=4" class="prev_page">« Previous<\/a>/)
|
||||
html.should match(/<span class="disabled next_page">Next »<\/span>/)
|
||||
|
||||
pagination.merge!({ 'parts' => [] })
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should == ''
|
||||
end
|
||||
|
||||
def build_context
|
||||
klass = Class.new
|
||||
klass.class_eval do
|
||||
|
@ -2,29 +2,10 @@ require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Filters::Misc do
|
||||
|
||||
include Locomotive::Liquid::Filters::Base
|
||||
include Locomotive::Liquid::Filters::Misc
|
||||
|
||||
it 'should underscore an input' do
|
||||
underscore('foo').should == 'foo'
|
||||
underscore('home page').should == 'home_page'
|
||||
underscore('My foo Bar').should == 'my_foo_bar'
|
||||
underscore('foo/bar').should == 'foo_bar'
|
||||
underscore('foo/bar/index').should == 'foo_bar_index'
|
||||
end
|
||||
|
||||
it 'should dasherize an input' do
|
||||
dasherize('foo').should == 'foo'
|
||||
dasherize('foo_bar').should == 'foo-bar'
|
||||
dasherize('foo/bar').should == 'foo-bar'
|
||||
dasherize('foo/bar/index').should == 'foo-bar-index'
|
||||
end
|
||||
|
||||
it 'should concat strings' do
|
||||
concat('foo', 'bar').should == 'foobar'
|
||||
concat('hello', 'foo', 'bar').should == 'hellofoobar'
|
||||
end
|
||||
|
||||
it 'should return the input string every n occurences' do
|
||||
it 'returns the input string every n occurences' do
|
||||
modulo('foo', 0, 3).should == ''
|
||||
modulo('foo', 1, 3).should == ''
|
||||
modulo('foo', 2, 3).should == 'foo'
|
||||
@ -33,4 +14,43 @@ describe Locomotive::Liquid::Filters::Misc do
|
||||
modulo('foo', 5, 3).should == 'foo'
|
||||
end
|
||||
|
||||
it 'returns default values if the input is empty' do
|
||||
default('foo', 42).should == 'foo'
|
||||
default('', 42).should == 42
|
||||
default(nil, 42).should == 42
|
||||
end
|
||||
|
||||
it 'should return a navigation block for the pagination' do
|
||||
pagination = {
|
||||
"previous" => nil,
|
||||
"parts" => [
|
||||
{ 'title' => '1', 'is_link' => false },
|
||||
{ 'title' => '2', 'is_link' => true, 'url' => '/?page=2' },
|
||||
{ 'title' => '…', 'is_link' => false, 'hellip_break' => true },
|
||||
{ 'title' => '5', 'is_link' => true, 'url' => '/?page=5' }
|
||||
],
|
||||
"next" => { 'title' => 'next', 'is_link' => true, 'url' => '/?page=2' }
|
||||
}
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should match(/<div class="pagination flickr_pagination">/)
|
||||
html.should match(/<span class="disabled prev_page">« Previous<\/span>/)
|
||||
html.should match(/<a href="\/\?page=2">2<\/a>/)
|
||||
html.should match(/<span class=\"gap\">\…<\/span>/)
|
||||
html.should match(/<a href="\/\?page=2" class="next_page">Next »<\/a>/)
|
||||
|
||||
pagination.merge!({
|
||||
'previous' => { 'title' => 'previous', 'is_link' => true, 'url' => '/?page=4' },
|
||||
'next' => nil
|
||||
})
|
||||
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should_not match(/<span class="disabled prev_page">« Previous<\/span>/)
|
||||
html.should match(/<a href="\/\?page=4" class="prev_page">« Previous<\/a>/)
|
||||
html.should match(/<span class="disabled next_page">Next »<\/span>/)
|
||||
|
||||
pagination.merge!({ 'parts' => [] })
|
||||
html = default_pagination(pagination, 'css:flickr_pagination')
|
||||
html.should == ''
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -8,4 +8,25 @@ describe Locomotive::Liquid::Filters::Text do
|
||||
textile('This is *my* text.').should == "<p>This is <strong>my</strong> text.</p>"
|
||||
end
|
||||
|
||||
it 'underscores an input' do
|
||||
underscore('foo').should == 'foo'
|
||||
underscore('home page').should == 'home_page'
|
||||
underscore('My foo Bar').should == 'my_foo_bar'
|
||||
underscore('foo/bar').should == 'foo_bar'
|
||||
underscore('foo/bar/index').should == 'foo_bar_index'
|
||||
end
|
||||
|
||||
it 'dasherizes an input' do
|
||||
dasherize('foo').should == 'foo'
|
||||
dasherize('foo_bar').should == 'foo-bar'
|
||||
dasherize('foo/bar').should == 'foo-bar'
|
||||
dasherize('foo/bar/index').should == 'foo-bar-index'
|
||||
end
|
||||
|
||||
it 'concats strings' do
|
||||
concat('foo', 'bar').should == 'foobar'
|
||||
concat('hello', 'foo', 'bar').should == 'hellofoobar'
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
@ -2,14 +2,14 @@ require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Tags::Paginate do
|
||||
|
||||
it 'should have a valid syntax' do
|
||||
it 'has a valid syntax' do
|
||||
markup = "contents.projects by 5"
|
||||
lambda do
|
||||
Locomotive::Liquid::Tags::Paginate.new('paginate', markup, ["{% endpaginate %}"], {})
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it 'should raise an error if the syntax is incorrect' do
|
||||
it 'raises 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 %}"], {})
|
||||
@ -17,9 +17,9 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
end
|
||||
end
|
||||
|
||||
it 'should paginate the collection' do
|
||||
template = Liquid::Template.parse(default_template)
|
||||
text = template.render!(liquid_context)
|
||||
it 'paginates the collection' do
|
||||
template = Liquid::Template.parse(default_template)
|
||||
text = template.render!(liquid_context)
|
||||
|
||||
text.should match /!Ruby on Rails!/
|
||||
text.should match /!jQuery!/
|
||||
@ -33,7 +33,7 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
text.should_not match /!sqlite3!/
|
||||
end
|
||||
|
||||
it 'should not paginate if collection is nil or empty' do
|
||||
it 'does not paginate if collection is nil or empty' do
|
||||
template = Liquid::Template.parse(default_template)
|
||||
|
||||
lambda do
|
||||
@ -45,6 +45,20 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
end.should raise_error
|
||||
end
|
||||
|
||||
it 'keeps the original GET parameters' do
|
||||
context = liquid_context(:fullpath => '/products?foo=1&bar=1&baz=1')
|
||||
template = Liquid::Template.parse(default_template)
|
||||
text = template.render!(context)
|
||||
text.should match /\/products\?foo=1&bar=1&baz=1&page=2/
|
||||
end
|
||||
|
||||
it 'does not include twice the page parameter' do
|
||||
context = liquid_context(:fullpath => '/products?page=1')
|
||||
template = Liquid::Template.parse(default_template)
|
||||
text = template.render!(context)
|
||||
text.should match /\/products\?page=2/
|
||||
end
|
||||
|
||||
# ___ helpers methods ___ #
|
||||
|
||||
def liquid_context(options = {})
|
||||
@ -53,7 +67,8 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
{
|
||||
'projects' => options.has_key?(:collection) ? options[:collection] : PaginatedCollection.new(['Ruby on Rails', 'jQuery', 'mongodb', 'Liquid', 'sqlite3']),
|
||||
'current_page' => options[:page] || 1,
|
||||
'path' => '/'
|
||||
'path' => '/',
|
||||
'fullpath' => options[:fullpath] || '/'
|
||||
}, {
|
||||
:page => FactoryGirl.build(:page)
|
||||
}, true)
|
||||
@ -64,6 +79,7 @@ describe Locomotive::Liquid::Tags::Paginate do
|
||||
{% for project in paginate.collection %}
|
||||
!{{ project }}!
|
||||
{% endfor %}
|
||||
{{ paginate.next.url }}
|
||||
{% endpaginate %}"
|
||||
end
|
||||
|
||||
|
@ -83,25 +83,25 @@ describe 'Locomotive rendering system' do
|
||||
|
||||
it 'should retrieve the index page /' do
|
||||
@controller.request.fullpath = '/'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 0, :fullpath.in => %w{index}).returns([@page])
|
||||
@controller.send(:locomotive_page).should_not be_nil
|
||||
end
|
||||
|
||||
it 'should also retrieve the index page (index.html)' do
|
||||
@controller.request.fullpath = '/index.html'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 0, :fullpath.in => %w{index}).returns([@page])
|
||||
@controller.send(:locomotive_page).should_not be_nil
|
||||
end
|
||||
|
||||
it 'should retrieve it based on the full path' do
|
||||
@controller.request.fullpath = '/about_us/team.html'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{about_us/team about_us/content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 2, :fullpath.in => %w{about_us/team about_us/content_type_template content_type_template/team}).returns([@page])
|
||||
@controller.send(:locomotive_page).should_not be_nil
|
||||
end
|
||||
|
||||
it 'does not include the query string' do
|
||||
@controller.request.fullpath = '/about_us/team.html?some=params&we=use'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{about_us/team about_us/content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 2, :fullpath.in => %w{about_us/team about_us/content_type_template content_type_template/team}).returns([@page])
|
||||
@controller.send(:locomotive_page).should_not be_nil
|
||||
end
|
||||
|
||||
@ -118,7 +118,7 @@ describe 'Locomotive rendering system' do
|
||||
@page.redirect = true
|
||||
@page.redirect_url = 'http://www.example.com/'
|
||||
@controller.request.fullpath = '/contact'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 1, :fullpath.in => %w{contact content_type_template}).returns([@page])
|
||||
end
|
||||
|
||||
it 'redirects to the redirect_url' do
|
||||
@ -135,13 +135,15 @@ describe 'Locomotive rendering system' do
|
||||
@content_entry = @content_type.entries.build(:_visible => true)
|
||||
@page.templatized = true
|
||||
@page.stubs(:fetch_target_entry).returns(@content_entry)
|
||||
@page.stubs(:fullpath).returns('/projects/content_type_template')
|
||||
@controller.request.fullpath = '/projects/edeneo.html'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{projects/edeneo projects/content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 2, :fullpath.in => %w{projects/edeneo projects/content_type_template content_type_template/edeneo}).returns([@page])
|
||||
end
|
||||
|
||||
it 'sets the content_entry variable' do
|
||||
@controller.send(:locomotive_page).should_not be_nil
|
||||
@controller.instance_variable_get(:@content_entry).should == @content_entry
|
||||
page = @controller.send(:locomotive_page)
|
||||
page.should_not be_nil
|
||||
page.content_entry.should == @content_entry
|
||||
end
|
||||
|
||||
it 'returns the 404 page if the instance does not exist' do
|
||||
@ -149,7 +151,6 @@ describe 'Locomotive rendering system' do
|
||||
(klass = Locomotive::Page).expects(:published).returns([true])
|
||||
@controller.current_site.pages.expects(:not_found).returns(klass)
|
||||
@controller.send(:locomotive_page).should be_true
|
||||
@controller.instance_variable_get(:@content_entry).should be_nil
|
||||
end
|
||||
|
||||
it 'returns the 404 page if the instance is not visible' do
|
||||
@ -171,7 +172,7 @@ describe 'Locomotive rendering system' do
|
||||
|
||||
it 'should return the 404 page if the page has not been published yet' do
|
||||
@controller.request.fullpath = '/contact'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 1, :fullpath.in => %w{contact content_type_template}).returns([@page])
|
||||
(klass = Locomotive::Page).expects(:published).returns([true])
|
||||
@controller.current_site.pages.expects(:not_found).returns(klass)
|
||||
@controller.send(:locomotive_page).should be_true
|
||||
@ -180,7 +181,7 @@ describe 'Locomotive rendering system' do
|
||||
it 'should not return the 404 page if the page has not been published yet and admin is logged in' do
|
||||
@controller.current_locomotive_account = true
|
||||
@controller.request.fullpath = '/contact'
|
||||
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
|
||||
@controller.current_site.pages.expects(:where).with(:depth => 1, :fullpath.in => %w{contact content_type_template}).returns([@page])
|
||||
@controller.send(:locomotive_page).should == @page
|
||||
end
|
||||
|
||||
|
@ -203,12 +203,30 @@ describe Locomotive::Page do
|
||||
|
||||
end
|
||||
|
||||
describe 'render module' do
|
||||
|
||||
context '#path combinations' do
|
||||
|
||||
it 'generates them for a path depth equals to 1' do
|
||||
Locomotive::Page.path_combinations('foo').should == ['foo', 'content_type_template']
|
||||
end
|
||||
|
||||
it 'generates them for a path depth equals to 2' do
|
||||
Locomotive::Page.path_combinations('foo/bar').should == ['foo/bar', 'foo/content_type_template', 'content_type_template/bar']
|
||||
end
|
||||
|
||||
it 'generates them for a path depth equals to 3' do
|
||||
Locomotive::Page.path_combinations('foo/bar/baz').should == ['foo/bar/baz', 'foo/bar/content_type_template', 'foo/content_type_template/baz', 'content_type_template/bar/baz']
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'templatized extension' do
|
||||
|
||||
before(:each) do
|
||||
@page = FactoryGirl.build(:page, :templatized => true, :target_klass_name => 'Foo')
|
||||
# @page.stubs(:target_klass)
|
||||
# Locomotive::ContentType.stubs(:find).returns(FactoryGirl.build(:content_type, :site => nil))
|
||||
@page = FactoryGirl.build(:page, :parent => Factory.build(:page, :templatized => false), :templatized => true, :target_klass_name => 'Foo')
|
||||
end
|
||||
|
||||
it 'is considered as a templatized page' do
|
||||
@ -233,6 +251,44 @@ describe Locomotive::Page do
|
||||
@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
|
||||
|
Loading…
Reference in New Issue
Block a user