sort contents within a conten type + make content type validation more robust + find a bug when dealing with 2 content types

This commit is contained in:
dinedine 2010-05-26 02:41:10 +02:00
parent 4534a11ce4
commit 1a2467acf4
18 changed files with 99 additions and 37 deletions

View File

@ -6,7 +6,7 @@ module Admin
before_filter :set_content_type
def index
@contents = @content_type.contents
@contents = @content_type.ordered_contents
end
def new
@ -42,7 +42,11 @@ module Admin
end
def sort
@content_type.sort_contents!(params[:order])
flash_success!
redirect_to admin_contents_url(@content_type.slug)
end
def destroy

View File

@ -19,15 +19,13 @@ module Admin::BaseHelper
css = "#{'on' if name == sections(:sub)} #{'links' if block_given?} #{options[:css]}"
label_link = default_options[:i18n] ? t("admin.shared.menu.#{name}") : name
# if block_given?
# popup = content_tag(:div, capture(&block), :class => 'popup', :style => 'display: none')
# link = link_to(content_tag(:span, label_link + content_tag(:em)), url)
# concat(content_tag(:li, link + popup, :class => css))
# else
# html = content_tag(:li, link_to(content_tag(:span, label_link), url), :class => css)
# end
content_tag(:li, link_to(content_tag(:span, label_link), url), :class => css)
if block_given?
popup = content_tag(:div, capture(&block), :class => 'popup', :style => 'display: none')
link = link_to(content_tag(:span, preserve(label_link + content_tag(:em))), url)
content_tag(:li, link + popup, :class => css)
else
content_tag(:li, link_to(content_tag(:span, label_link), url), :class => css)
end
end
end

View File

@ -8,7 +8,7 @@ module Admin::CustomFieldsHelper
end
def options_for_order_by(content_type, collection_name)
options = %w{updated_at position}.map do |type|
options = %w{updated_at _position_in_list}.map do |type|
[t("admin.content_types.form.order_by.#{type.gsub(/^_/, '')}"), type]
end
options + options_for_highlighted_field(content_type, collection_name)

View File

@ -3,7 +3,7 @@ class ContentInstance
include Mongoid::Timestamps
## fields (dynamic fields) ##
field :position, :type => Integer, :default => 0
field :_position_in_list, :type => Integer, :default => 0
## validations ##
validate :require_highlighted_field
@ -11,6 +11,9 @@ class ContentInstance
## associations ##
embedded_in :content_type, :inverse_of => :contents
## named scopes ##
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
## methods ##
protected

View File

@ -16,10 +16,12 @@ class ContentType
## callbacks ##
before_validate :normalize_slug
before_save :set_default_values
## validations ##
validates_presence_of :site, :name, :slug
validates_uniqueness_of :slug, :scope => :site
validates_size_of :content_custom_fields, :minimum => 1, :message => :array_too_short
## behaviours ##
custom_fields_for :contents
@ -27,15 +29,15 @@ class ContentType
## methods ##
def ordered_contents
self.contents.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
column = self.order_by.to_sym
self.contents.sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
end
def contents_order
self.ordered_contents.collect(&:id).join(',')
end
def contents_order=(order)
@contents_order = order
def sort_contents!(order)
order.split(',').each_with_index do |id, position|
self.contents.find(id)._position_in_list = position
end
self.save
end
def highlighted_field
@ -44,6 +46,11 @@ class ContentType
protected
def set_default_values
self.order_by ||= 'updated_at'
self.highlighted_field_name ||= self.content_custom_fields.first._name
end
def normalize_slug
self.slug = self.name.clone if self.slug.blank? && self.name.present?
self.slug.slugify! if self.slug.present?

View File

@ -33,6 +33,7 @@ class Page
validates_exclusion_of :slug, :in => Locomotive.config.reserved_slugs, :if => Proc.new { |p| p.depth == 0 }
## named scopes ##
named_scope :latest_updated, :order_by => [[:updated_at, :desc]], :limit => Locomotive.config.lastest_items_nb
## behaviours ##
acts_as_tree :order => ['position', 'asc']

View File

@ -1,5 +1,7 @@
- highlighted_field_name = @content.content_type.highlighted_field_name
- puts "current custom fields = #{@content.custom_fields.inspect}"
= f.inputs :name => :other_fields do
- @content.custom_fields.each do |field|
- required = highlighted_field_name == field._name

View File

@ -5,6 +5,7 @@
- content_for :buttons do
= admin_button_tag t('admin.contents.index.edit'), edit_admin_content_type_url(@content_type), :class => 'edit'
= admin_button_tag t('admin.contents.index.new'), new_admin_content_url(@content_type.slug), :class => 'new'
%p= @content_type.description

View File

@ -8,7 +8,6 @@
- content_for :buttons do
= admin_button_tag :edit, edit_admin_content_type_url(@content_type), :class => 'edit'
= admin_button_tag :download, '#', :class => 'download'
= admin_button_tag :new, new_admin_content_url(@content_type.slug), :class => 'new'
- if @content_type.description.present?
@ -17,11 +16,10 @@
- if @contents.empty?
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
- else
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == 'position'}" }
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
- @contents.each do |content|
%li.content{ :id => "content-#{content._id}" }
- if @content_type.order_by == 'position'
%em
%em
%strong
= link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content)
.more

View File

@ -1,9 +1,27 @@
%ul
= admin_submenu_item 'pages', admin_pages_url
= admin_submenu_item 'pages', admin_pages_url do
.header
%p= link_to t('admin.pages.index.new'), new_admin_page_url
.inner
%h2= t('admin.pages.index.lastest_items')
%ul
- current_site.pages.latest_updated.each do |page|
%li
= link_to truncate(page.title, :length => 40), edit_admin_page_url(page)
%span= time_ago_in_words(page.updated_at)
- current_site.content_types.each do |content_type|
- item_on = (content_type.slug == @content_type.slug) rescue nil
= admin_submenu_item content_type.name, admin_contents_url(content_type.slug), :i18n => false, :css => (item_on ? 'on' : '')
= admin_submenu_item content_type.name, admin_contents_url(content_type.slug), :i18n => false, :css => (item_on ? 'on' : '') do
.header
%p= link_to t('admin.contents.index.new'), new_admin_content_url(content_type.slug)
.inner
%h2= t('admin.contents.index.lastest_items')
%ul
- content_type.contents.latest_updated.each do |content|
%li
= link_to truncate(content.send(content_type.highlighted_field_name), :length => 40), edit_admin_content_path(content_type.slug, content)
%span= time_ago_in_words(content.updated_at)
.action
= link_to content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url

View File

@ -3,6 +3,8 @@ require 'lib/core_ext.rb'
Locomotive.configure do |config|
config.default_domain = 'example.com'
config.lastest_items_nb = 5
end
# TODO: embed them in Locomotive right after configure

View File

@ -60,6 +60,7 @@ en:
title: Listing pages
no_items: "There are no pages for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
new: new page
lastest_items: Lastest pages
page:
updated_at: updated at
edit:
@ -153,15 +154,17 @@ en:
form:
order_by:
updated_at: 'By "updated at" date'
position: Manually
position_in_list: Manually
contents:
index:
title: 'Listing "{{type}}"'
edit: edit model
destroy: remove model
download: download items
new: new item
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
lastest_items: "Lastest items"
new:
title: '{{type}} &mdash; new item'
edit:

View File

@ -7,6 +7,7 @@ en:
needs_admin_account: "One admin account is required at least"
protected_page: "You can not remove index or 404 pages"
extname_changed: "New file does not have the original extension"
array_too_short: "is too small (minimum element number is {{count}})"
attributes:
defaults:

View File

@ -1,9 +1,5 @@
BOARD:
- content types / models (CRUD)
- require a custom field at least
- pre-select the first custom field as the highlighted one
- contents (CRUD)
- sort contents
- contents sub menu => BUG
BACKLOG:
- liquid rendering engine
@ -79,3 +75,8 @@ x custom fields:
x nested attributes
x keep tracks of all custom fields (adding / editing assets) + order them
x duplicate fields
x content types / models (CRUD)
x require a custom field at least
x pre-select the first custom field as the highlighted one
x contents (CRUD)
x sort contents

View File

@ -44,6 +44,18 @@ var addCodeMirrorEditor = function(type, el, parser) {
$(document).ready(function() {
I18nLocale = $('meta[name=locale]').attr('content');
// sub menu links
$('#submenu ul li.links').hover(function() {
$(this).addClass('hover');
$(this).find('.popup').show();
}, function() {
$(this).removeClass('hover');
$(this).find('.popup').hide();
});
if ((css = $('#submenu > ul').attr('class')) != '')
$('#submenu > ul > li.' + css).addClass('on');
// form
$('.formtastic li input, .formtastic li textarea').focus(function() {
$('.formtastic li.error p.inline-errors').fadeOut(200);

View File

@ -9,6 +9,7 @@ $(document).ready(function() {
}
$('ul#contents-list.sortable').sortable({
handle: 'em',
items: 'li.content',
stop: function(event, ui) { updateContentsOrder(); }
});

View File

@ -163,7 +163,7 @@ div#uploadAssetsInputQueue { display: none; }
#contents-list li { background: none; }
#contents-list li em {
#contents-list.sortable li em {
background-position: left -31px;
cursor: move;
}

View File

@ -9,7 +9,9 @@ describe ContentType do
context 'when validating' do
it 'should have a valid factory' do
Factory.build(:content_type).should be_valid
content_type = Factory.build(:content_type)
content_type.content_custom_fields.build :label => 'anything', :kind => 'String'
content_type.should be_valid
end
# Validations ##
@ -29,11 +31,19 @@ describe ContentType do
end
it 'should validate uniqueness of slug' do
content_type = Factory(:content_type)
content_type = Factory.build(:content_type)
content_type.content_custom_fields.build :label => 'anything', :kind => 'String'
content_type.save
(content_type = Factory.build(:content_type, :site => content_type.site)).should_not be_valid
content_type.errors[:slug].should == ["is already taken"]
end
it 'should validate size of content custom fields' do
content_type = Factory.build(:content_type)
content_type.should_not be_valid
content_type.errors[:content_custom_fields].should == ["is too small (minimum element number is 1)"]
end
end
end