Merge remote-tracking branch 'origin/2.0.0.rc' into 2.0.0.rc

This commit is contained in:
Mario Visic 2012-04-02 19:28:21 +08:00
commit 114218b8c4
41 changed files with 589 additions and 325 deletions

View File

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

View File

@ -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'))

View File

@ -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']

View File

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

View File

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

View File

@ -11,6 +11,7 @@ body {
width: 100%;
height: 100%;
display: block;
min-height: 100%;
}
}

View File

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

View File

@ -7,6 +7,7 @@ module Locomotive
included do
## fields ##
field :listed, :type => Boolean, :default => true
end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,3 @@
module Locomotive #:nodoc
VERSION = '2.0.0.rc2'
VERSION = '2.0.0.rc3'
end

View File

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

View File

@ -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,'

View File

@ -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' => '&hellip;', '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">&laquo; Previous<\/span>/)
html.should match(/<a href="\/\?page=2">2<\/a>/)
html.should match(/<span class=\"gap\">\&hellip;<\/span>/)
html.should match(/<a href="\/\?page=2" class="next_page">Next &raquo;<\/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">&laquo; Previous<\/span>/)
html.should match(/<a href="\/\?page=4" class="prev_page">&laquo; Previous<\/a>/)
html.should match(/<span class="disabled next_page">Next &raquo;<\/span>/)
pagination.merge!({ 'parts' => [] })
html = default_pagination(pagination, 'css:flickr_pagination')
html.should == ''
end
def build_context
klass = Class.new
klass.class_eval do

View File

@ -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' => '&hellip;', '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">&laquo; Previous<\/span>/)
html.should match(/<a href="\/\?page=2">2<\/a>/)
html.should match(/<span class=\"gap\">\&hellip;<\/span>/)
html.should match(/<a href="\/\?page=2" class="next_page">Next &raquo;<\/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">&laquo; Previous<\/span>/)
html.should match(/<a href="\/\?page=4" class="prev_page">&laquo; Previous<\/a>/)
html.should match(/<span class="disabled next_page">Next &raquo;<\/span>/)
pagination.merge!({ 'parts' => [] })
html = default_pagination(pagination, 'css:flickr_pagination')
html.should == ''
end
end

View File

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

View File

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

View File

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

View File

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