templatized page + fix bug with nav widget

This commit is contained in:
dinedine 2010-07-16 22:36:07 +02:00
parent 56d7fddcfb
commit fb148a31a4
20 changed files with 177 additions and 21 deletions

View File

@ -7,6 +7,7 @@ class ContentInstance
include CustomFields::ProxyClassEnabler include CustomFields::ProxyClassEnabler
## fields (dynamic fields) ## ## fields (dynamic fields) ##
field :_slug
field :_position_in_list, :type => Integer, :default => 0 field :_position_in_list, :type => Integer, :default => 0
## validations ## ## validations ##
@ -16,6 +17,7 @@ class ContentInstance
embedded_in :content_type, :inverse_of => :contents embedded_in :content_type, :inverse_of => :contents
## callbacks ## ## callbacks ##
before_save :set_slug
before_create :add_to_list_bottom before_create :add_to_list_bottom
## named scopes ## ## named scopes ##
@ -29,16 +31,29 @@ class ContentInstance
protected protected
def set_slug
_alias = self.highlighted_field_alias
self._slug = self.send(_alias).parameterize('_')
end
def add_to_list_bottom def add_to_list_bottom
Rails.logger.debug "add_to_list_bottom" Rails.logger.debug "add_to_list_bottom"
self._position_in_list = self.content_type.contents.size self._position_in_list = self.content_type.contents.size
end end
def require_highlighted_field def require_highlighted_field
_alias = self.content_type.highlighted_field._alias.to_sym _alias = self.highlighted_field_alias
if self.send(_alias).blank? if self.send(_alias).blank?
self.errors.add(_alias, :blank) self.errors.add(_alias, :blank)
end end
end end
def highlighted_field_value
self.send(self.content_type.highlighted_field._name)
end
def highlighted_field_alias
self.content_type.highlighted_field._alias.to_sym
end
end end

View File

@ -0,0 +1,32 @@
module Models
module Extensions
module Page
module Templatized
extend ActiveSupport::Concern
included do
belongs_to_related :content_type
field :templatized, :type => Boolean, :default => false
field :content_type_visible_column
before_validate :set_slug_if_templatized
end
module InstanceMethods
def set_slug_if_templatized
self.slug = 'content_type_template' if self.templatized?
end
end
end
end
end
end

View File

@ -6,6 +6,7 @@ class Page
include Models::Extensions::Page::Tree include Models::Extensions::Page::Tree
include Models::Extensions::Page::Parts include Models::Extensions::Page::Parts
include Models::Extensions::Page::Render include Models::Extensions::Page::Render
include Models::Extensions::Page::Templatized
## fields ## ## fields ##
field :title field :title
@ -31,8 +32,8 @@ class Page
## named scopes ## ## named scopes ##
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
named_scope :index, :where => { :slug => 'index', :depth => 0, :published => true } named_scope :index, :where => { :slug => 'index', :depth => 0 }
named_scope :not_found, :where => { :slug => '404', :depth => 0, :published => true } named_scope :not_found, :where => { :slug => '404', :depth => 0 }
named_scope :published, :where => { :published => true } named_scope :published, :where => { :published => true }
## behaviours ## ## behaviours ##

View File

@ -11,8 +11,13 @@
- if not @page.index? and not @page.not_found? - if not @page.index? and not @page.not_found?
= f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false = f.input :parent_id, :as => :select, :collection => parent_pages_options, :include_blank => false
= f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : @page.url, :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? } = f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : @page.url, :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}" }
= f.custom_input :templatized, :css => 'toggle' do
= f.check_box :templatized
= f.input :content_type_id, :as => :select, :collection => current_site.content_types.all.to_a, :include_blank => false, :wrapper_html => { :style => "#{'display: none' unless @page.templatized?}" }
= f.custom_input :published, :css => 'toggle' do = f.custom_input :published, :css => 'toggle' do
= f.check_box :published = f.check_box :published

View File

@ -1,4 +1,4 @@
%li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? }"} %li{ :id => "item-#{page.id}", :class => "#{'not-found' if page.not_found? } #{'templatized' if page.templatized?}"}
- if not page.index? and not page.children.empty? - if not page.index? and not page.children.empty?
= image_tag 'admin/list/icons/node_closed.png', :class => 'toggler' = image_tag 'admin/list/icons/node_closed.png', :class => 'toggler'
%em %em

View File

@ -268,6 +268,7 @@ en:
page: page:
published: "Only authenticated accounts can view unpublished pages." published: "Only authenticated accounts can view unpublished pages."
cache_strategy: "Cache the page for better performance. The 'Simple' choice is a good compromise." cache_strategy: "Cache the page for better performance. The 'Simple' choice is a good compromise."
templatized: "Use the page as a template for a model you defined."
snippet: snippet:
slug: "You need to know it in order to insert the snippet inside a page or a layout" slug: "You need to know it in order to insert the snippet inside a page or a layout"
site: site:

View File

@ -290,6 +290,7 @@ fr:
page: page:
published: "Seuls les administrateurs authentifiés peuvent voir une page non publiée." published: "Seuls les administrateurs authentifiés peuvent voir une page non publiée."
cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis." cache_strategy: "Cache la page pour de meilleure performance. L'option 'Simple' est le meilleur compromis."
templatized: "Utilise la page comme un template pour un modèle défini."
snippet: snippet:
slug: "Utilisé pour insérer le snippet dans une page ou un gabarit." slug: "Utilisé pour insérer le snippet dans une page ou un gabarit."
site: site:

View File

@ -2,7 +2,7 @@ BOARD:
- refactor slugify method (use parameterize + create a module) - refactor slugify method (use parameterize + create a module)
- send email when new content added thru api - send email when new content added thru api
- page templatized (bound to a model) - shortcut for jquery include tag
BACKLOG: BACKLOG:
@ -61,4 +61,5 @@ x refactoring admin crud (pages + layouts + snippets)
x flash messages in French x flash messages in French
x save layout / snippet / page / stylesheet / javascript with CMD + S (ajax) x save layout / snippet / page / stylesheet / javascript with CMD + S (ajax)
x change action icons according to the right action [Sacha] x change action icons according to the right action [Sacha]
x publish event when saving form in ajax (for instance, in order to update account name or site name) x publish event when saving form in ajax (for instance, in order to update account name or site name)
x page templatized (bound to a model)

View File

@ -11,7 +11,9 @@ module Locomotive
end end
end end
def highlighted_field_value
@source.highlighted_field_value
end
end end
end end

View File

@ -3,7 +3,15 @@ module Locomotive
module Drops module Drops
class Page < Base class Page < Base
liquid_attributes << :title << :slug # liquid_attributes << :title << :slug
def title
@source.templatized? ? @context['content_instance'].highlighted_field_value : @source.title
end
def slug
@source.templatized? ? @source.content_type.slug.singularize : @source.slug
end
def children def children
@children ||= liquify(*@source.children) @children ||= liquify(*@source.children)

View File

@ -29,10 +29,12 @@ module Locomotive
source = context.registers[@site_or_page.to_sym] source = context.registers[@site_or_page.to_sym]
puts "#{@site_or_page.to_sym} / source = #{source.inspect}"
if source.respond_to?(:name) # site ? if source.respond_to?(:name) # site ?
source = source.pages.first # start from home page source = source.pages.index.first # start from home page
else else
source = source.parent source = source.parent || source
end end
output = %{<ul id="nav">} output = %{<ul id="nav">}

View File

@ -23,9 +23,24 @@ module Locomotive
path.gsub!(/^\//, '') path.gsub!(/^\//, '')
path = 'index' if path.blank? path = 'index' if path.blank?
if page = current_site.pages.where(:fullpath => path).first if path != 'index'
dirname = File.dirname(path).gsub(/^\.$/, '') # also look for templatized page path
path = [path, File.join(dirname, 'content_type_template').gsub(/^\//, '')]
end
# TODO: path is not correctly built + find content instance in order to render a 404 page if not found
if page = current_site.pages.any_in(:fullpath => [*path]).first
if not page.published? and current_admin.nil? if not page.published? and current_admin.nil?
page = nil page = nil
else
if page.templatized?
@content_instance = page.content_type.contents.where(:_slug => File.basename(path.first)).first
if @content_instance.nil? # content instance not found
page = nil
end
end
end end
end end
@ -43,6 +58,11 @@ module Locomotive
'current_page' => self.params[:page] 'current_page' => self.params[:page]
} }
if @page.templatized? # add instance from content type
assigns['content_instance'] = @content_instance
assigns[@page.content_type.slug.singularize] = @content_instance # just here to help to write readable liquid code
end
registers = { :controller => self, :site => current_site, :page => @page } registers = { :controller => self, :site => current_site, :page => @page }
::Liquid::Context.new(assigns, registers) ::Liquid::Context.new(assigns, registers)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -31,6 +31,19 @@ $(document).ready(function() {
} }
}); });
// templatized feature
$.subscribe('toggle.page_templatized.checked', function(event, data) {
$('#page_slug_input').hide();
$('#page_content_type_id_input').show();
}, []);
$.subscribe('toggle.page_templatized.unchecked', function(event, data) {
$('#page_slug_input').show();
$('#page_slug').val(makeSlug($('#page_title').val())).addClass('touched');
$('#page_content_type_id_input').hide();
}, []);
// automatic slug from page title // automatic slug from page title
$('#page_title').keypress(function() { $('#page_title').keypress(function() {
var input = $(this); var input = $(this);

View File

@ -64,6 +64,8 @@
$(element).parent().css("background-color", settings.off_bg_color); $(element).parent().css("background-color", settings.off_bg_color);
$(element).parent().parent().prev().removeAttr("checked"); $(element).parent().parent().prev().removeAttr("checked");
$(element).removeClass("left").addClass("right"); $(element).removeClass("left").addClass("right");
$.publish('toggle.' + $(element).parent().parent().prev().attr('id') + '.unchecked', []);
}); });
}else{ }else{
@ -78,6 +80,7 @@
$(element).parent().parent().prev().attr("checked","checked"); $(element).parent().parent().prev().attr("checked","checked");
$(element).removeClass("right").addClass("left"); $(element).removeClass("right").addClass("left");
$.publish('toggle.' + $(element).parent().parent().prev().attr('id') + '.checked', []);
}); });
} }

View File

@ -117,7 +117,7 @@ ul.assets li.asset.last {
margin-right: 0px; margin-right: 0px;
} }
ul.assets li.asset h4 { margin: 0px; height: 30px; border-bottom: 1px solid #C2C4D2; } ul.assets li.asset h4 { margin: 0px; height: 30px; border-bottom: 1px solid #ccced7; }
ul.assets li.asset h4 a { ul.assets li.asset h4 a {
position: relative; position: relative;
@ -205,6 +205,11 @@ div#uploadAssetsInputQueue { display: none; }
cursor: move; cursor: move;
} }
#pages-list ul.folder li.templatized em {
background-position: left -62px;
cursor: pointer;
}
#pages-list li .toggler { #pages-list li .toggler {
position: absolute; position: absolute;
top: 9px; top: 9px;

View File

@ -80,7 +80,7 @@ form.formtastic fieldset.inputs ol {
padding-top: 15px; padding-top: 15px;
padding-bottom: 5px; padding-bottom: 5px;
background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom; background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom;
border-top: 1px solid #C2C4D2; border-top: 1px solid #ccced7;
} }
@media screen and (-webkit-min-device-pixel-ratio:0) { @media screen and (-webkit-min-device-pixel-ratio:0) {

View File

@ -2,7 +2,7 @@
background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom; background: #ebedf4 url(/images/admin/form/footer.png) no-repeat 0 bottom;
width: 880px; width: 880px;
padding: 20px 20px; padding: 20px 20px;
border-top: 1px solid #C2C4D2; border-top: 1px solid #ccced7;
} }
#page-parts { #page-parts {

View File

@ -52,19 +52,19 @@ describe 'Locomotive rendering system' do
it 'should retrieve the index page /' do it 'should retrieve the index page /' do
@controller.request.fullpath = '/' @controller.request.fullpath = '/'
@controller.current_site.pages.expects(:where).with({ :fullpath => 'index' }).returns([@page]) @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
@controller.send(:locomotive_page).should_not be_nil @controller.send(:locomotive_page).should_not be_nil
end end
it 'should also retrieve the index page (index.html)' do it 'should also retrieve the index page (index.html)' do
@controller.request.fullpath = '/index.html' @controller.request.fullpath = '/index.html'
@controller.current_site.pages.expects(:where).with({ :fullpath => 'index' }).returns([@page]) @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{index} }).returns([@page])
@controller.send(:locomotive_page).should_not be_nil @controller.send(:locomotive_page).should_not be_nil
end end
it 'should retrieve it based on the full path' do it 'should retrieve it based on the full path' do
@controller.request.fullpath = '/about_us/team.html' @controller.request.fullpath = '/about_us/team.html'
@controller.current_site.pages.expects(:where).with({ :fullpath => 'about_us/team' }).returns([@page]) @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{about_us/team about_us/content_type_template} }).returns([@page])
@controller.send(:locomotive_page).should_not be_nil @controller.send(:locomotive_page).should_not be_nil
end end
@ -74,6 +74,31 @@ describe 'Locomotive rendering system' do
@controller.send(:locomotive_page).should be_true @controller.send(:locomotive_page).should be_true
end end
context 'templatized page' do
before(:each) do
@content_type = Factory.build(:content_type, :site => nil)
@page.templatized = true
@page.content_type = @content_type
@controller.request.fullpath = '/projects/edeneo.html'
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{projects/edeneo projects/content_type_template} }).returns([@page])
end
it 'sets the content_instance variable' do
@content_type.contents.stubs(:where).returns([42])
@controller.send(:locomotive_page).should_not be_nil
@controller.instance_variable_get(:@content_instance).should == 42
end
it 'returns the 404 page if the instance does not exist' do
@content_type.contents.stubs(:where).returns([])
@controller.current_site.pages.expects(:not_found).returns([true])
@controller.send(:locomotive_page).should be_true
@controller.instance_variable_get(:@content_instance).should be_nil
end
end
context 'non published page' do context 'non published page' do
before(:each) do before(:each) do
@ -83,7 +108,7 @@ describe 'Locomotive rendering system' do
it 'should return the 404 page if the page has not been published yet' do it 'should return the 404 page if the page has not been published yet' do
@controller.request.fullpath = '/contact' @controller.request.fullpath = '/contact'
@controller.current_site.pages.expects(:where).with({ :fullpath => 'contact' }).returns([@page]) @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
@controller.current_site.pages.expects(:not_found).returns([true]) @controller.current_site.pages.expects(:not_found).returns([true])
@controller.send(:locomotive_page).should be_true @controller.send(:locomotive_page).should be_true
end end
@ -91,7 +116,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 it 'should not return the 404 page if the page has not been published yet and admin is logged in' do
@controller.current_admin = true @controller.current_admin = true
@controller.request.fullpath = '/contact' @controller.request.fullpath = '/contact'
@controller.current_site.pages.expects(:where).with({ :fullpath => 'contact' }).returns([@page]) @controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{contact content_type_template} }).returns([@page])
@controller.send(:locomotive_page).should == @page @controller.send(:locomotive_page).should == @page
end end

View File

@ -333,4 +333,26 @@ describe Page do
end end
end end
describe 'templatized extension' do
before(:each) do
@page = Factory.build(:page, :site => nil, :templatized => true, :content_type_id => 42)
ContentType.stubs(:find).returns(Factory.build(:content_type, :site => nil))
end
it 'is considered as a templatized page' do
@page.templatized?.should be_true
end
it 'fills in the slug field' do
@page.valid?
@page.slug.should == 'content_type_template'
end
it 'does forget to set the content type id' do
@page.content_type_id.should == '42'
end
end
end end