patch mongoid to enable the limit option for embedded collections + ui widget to allow more than 5 custom models in the content section

This commit is contained in:
did 2011-03-08 16:05:07 +01:00
parent c3cc358934
commit e4b34eac3f
11 changed files with 211 additions and 73 deletions

View File

@ -21,14 +21,13 @@ gem 'rmagick', '2.12.2'
gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave' gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave'
gem 'custom_fields', '1.0.0.beta.5' gem 'custom_fields', '1.0.0.beta.5'
# gem 'custom_fields', :path => '../gems/custom_fields'
gem 'fog', '0.3.7' gem 'fog', '0.3.7'
gem 'mimetype-fu' gem 'mimetype-fu'
gem 'actionmailer-with-request' gem 'actionmailer-with-request'
gem 'heroku' gem 'heroku', '1.18.2'
gem 'httparty', '>= 0.6.1' gem 'httparty', '>= 0.6.1'
gem 'RedCloth', '4.2.7' gem 'RedCloth', '4.2.7'
gem 'delayed_job', '2.1.2' gem 'delayed_job', '2.1.4'
gem 'delayed_job_mongoid', '1.0.2' gem 'delayed_job_mongoid', '1.0.2'
gem 'rubyzip' gem 'rubyzip'
gem 'locomotive_jammit-s3', :require => 'jammit-s3' gem 'locomotive_jammit-s3', :require => 'jammit-s3'

View File

@ -83,7 +83,7 @@ GEM
mongoid (~> 2.0.0.rc.7) mongoid (~> 2.0.0.rc.7)
daemons (1.1.0) daemons (1.1.0)
database_cleaner (0.6.4) database_cleaner (0.6.4)
delayed_job (2.1.2) delayed_job (2.1.4)
activesupport (~> 3.0) activesupport (~> 3.0)
daemons daemons
delayed_job_mongoid (1.0.2) delayed_job_mongoid (1.0.2)
@ -121,10 +121,10 @@ GEM
growl-glue (1.0.7) growl-glue (1.0.7)
haml (3.0.25) haml (3.0.25)
has_scope (0.5.0) has_scope (0.5.0)
heroku (1.6.3) heroku (1.18.2)
json (>= 1.1.0) json (~> 1.5.1)
launchy (>= 0.3.2) launchy (~> 0.3.2)
rest-client (>= 1.2.0, < 2.0.0) rest-client (>= 1.4.0, < 1.7.0)
httparty (0.7.4) httparty (0.7.4)
crack (= 0.1.8) crack (= 0.1.8)
i18n (0.5.0) i18n (0.5.0)
@ -137,7 +137,7 @@ GEM
json (1.5.1) json (1.5.1)
json_pure (1.4.6) json_pure (1.4.6)
kgio (2.3.2) kgio (2.3.2)
launchy (0.4.0) launchy (0.3.7)
configuration (>= 0.0.5) configuration (>= 0.0.5)
rake (>= 0.8.1) rake (>= 0.8.1)
linecache (0.43) linecache (0.43)
@ -266,7 +266,7 @@ DEPENDENCIES
cucumber-rails cucumber-rails
custom_fields (= 1.0.0.beta.5) custom_fields (= 1.0.0.beta.5)
database_cleaner database_cleaner
delayed_job (= 2.1.2) delayed_job (= 2.1.4)
delayed_job_mongoid (= 1.0.2) delayed_job_mongoid (= 1.0.2)
devise (= 1.1.3) devise (= 1.1.3)
factory_girl_rails factory_girl_rails
@ -274,7 +274,7 @@ DEPENDENCIES
formtastic (~> 1.2.3) formtastic (~> 1.2.3)
growl-glue growl-glue
haml (= 3.0.25) haml (= 3.0.25)
heroku heroku (= 1.18.2)
httparty (>= 0.6.1) httparty (>= 0.6.1)
inherited_resources (~> 1.1.2) inherited_resources (~> 1.1.2)
launchy launchy

View File

@ -0,0 +1,62 @@
module Admin::ContentTypesHelper
MAX_DISPLAYED_CONTENTS = 4
def fetch_content_types
return @content_types if @content_types
@content_types = current_site.content_types.ordered.
limit(:contents => Locomotive.config.lastest_items_nb).
only(:name, :slug, :highlighted_field_name, :updated_at).to_a
if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS
@content_types.delete(@content_type)
@content_types.insert(0, @content_type)
end
@content_types
end
def each_content_type_menu_item(which = :first, &block)
types = fetch_content_types
sliced = []
if which == :first
sliced = types[0..MAX_DISPLAYED_CONTENTS - 1]
elsif types.size > MAX_DISPLAYED_CONTENTS
sliced = types[MAX_DISPLAYED_CONTENTS, types.size - MAX_DISPLAYED_CONTENTS]
end
return [] if sliced.empty?
sliced.each do |content_type|
next if content_type.new_record?
item_on = (content_type.slug == @content_type.slug) rescue nil
label = truncate(content_type.name, :length => 15)
url = admin_contents_url(content_type.slug)
css = @content_type && content_type.slug == @content_type.slug ? 'on' : ''
html = admin_submenu_item(label, url, :i18n => false, :css => css) do
yield(content_type)
end
haml_concat(html)
end
end
def other_content_types(&block)
types = fetch_content_types
if types.size > MAX_DISPLAYED_CONTENTS
sliced = types[MAX_DISPLAYED_CONTENTS, types.size - MAX_DISPLAYED_CONTENTS]
html = admin_submenu_item('...', '#', :i18n => false) do
yield(sliced)
end
haml_concat(html)
end
end
end

View File

@ -21,7 +21,8 @@ class ContentType
end end
## named scopes ## ## named scopes ##
scope :first_by_slug, lambda { |slug| where(:slug => slug) } scope :ordered, :order_by => :updated_at.desc
## indexes ## ## indexes ##
index [[:site_id, Mongo::ASCENDING], [:slug, Mongo::ASCENDING]] index [[:site_id, Mongo::ASCENDING], [:slug, Mongo::ASCENDING]]

View File

@ -10,19 +10,23 @@
= link_to truncate(page.title, :length => 25), edit_admin_page_url(page) = link_to truncate(page.title, :length => 25), edit_admin_page_url(page)
%span= time_ago_in_words(page.updated_at) %span= time_ago_in_words(page.updated_at)
- current_site.content_types.to_a.each do |content_type| - each_content_type_menu_item do |content_type|
- next if content_type.new_record? .header
- item_on = (content_type.slug == @content_type.slug) rescue nil %p= link_to t('admin.contents.index.new'), new_admin_content_url(content_type.slug)
= admin_submenu_item content_type.name, admin_contents_url(content_type.slug), :i18n => false, :css => (item_on ? 'on' : '') do .inner
.header %h2!= t('admin.contents.index.lastest_items')
%p= link_to t('admin.contents.index.new'), new_admin_content_url(content_type.slug) %ul
.inner - content_type.contents.latest_updated.each do |content|
%h2!= t('admin.contents.index.lastest_items') %li
%ul = link_to truncate(content.send(content_type.highlighted_field_name), :length => 20), edit_admin_content_path(content_type.slug, content)
- content_type.contents.latest_updated.each do |content| %span= time_ago_in_words(content.updated_at)
%li
= link_to truncate(content.send(content_type.highlighted_field_name), :length => 30), edit_admin_content_path(content_type.slug, content) - other_content_types do |content_types|
%span= time_ago_in_words(content.updated_at) .inner
%ul.big-links
- content_types.each do |content_type|
%li
= link_to truncate(content_type.name, :length => 20), admin_contents_url(content_type.slug)
.action .action
= link_to content_tag(:em) + content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url = link_to content_tag(:em) + content_tag(:span, t('admin.content_types.index.new')), new_admin_content_type_url

View File

@ -16,7 +16,7 @@ require 'actionmailer_with_request'
require 'heroku' require 'heroku'
require 'httparty' require 'httparty'
require 'redcloth' require 'redcloth'
#require 'delayed_job_mongoid' require 'delayed_job_mongoid'
require 'zip/zipfilesystem' require 'zip/zipfilesystem'
require 'jammit-s3' require 'jammit-s3'

View File

@ -3,9 +3,9 @@ module Locomotive
module Tags module Tags
module Editable module Editable
class Content < ::Liquid::Tag class Content < ::Liquid::Tag
Syntax = /(#{::Liquid::Expression}+)?/ Syntax = /(#{::Liquid::Expression}+)?/
def initialize(tag_name, markup, tokens, context) def initialize(tag_name, markup, tokens, context)
if markup =~ Syntax if markup =~ Syntax
@slug = $1 @slug = $1
@ -17,31 +17,31 @@ module Locomotive
super super
end end
def render(context) def render(context)
page = context.registers[:page] page = context.registers[:page]
element = find_element(page) element = find_element(page)
if element.nil? && @options[:inherit] != false if element.nil? && @options[:inherit] != false
while page.parent.present? && element.nil? while page.parent.present? && element.nil?
page = page.parent page = page.parent
element = find_element(page) element = find_element(page)
end end
end end
if element.present? if element.present?
return element.content return element.content
else else
raise ::Liquid::SyntaxError.new("Error in 'content' - Can't find editable element called `#{@slug}`") raise ::Liquid::SyntaxError.new("Error in 'content' - Can't find editable element called `#{@slug}`")
end end
end end
def find_element(page) def find_element(page)
page.editable_elements.where(:slug => @slug).first page.editable_elements.where(:slug => @slug).first
end end
end end
::Liquid::Template.register_tag('content', Content) ::Liquid::Template.register_tag('content', Content)
end end
end end

View File

@ -1,3 +1,91 @@
# encoding: utf-8
require 'mongoid' require 'mongoid'
## For now, no mongoid monkey patch is required, that is a good thing after all :-) # Limit feature for embedded documents
module Mongoid #:nodoc:
module Criterion #:nodoc:
module Exclusion
def only(*args)
clone.tap do |crit|
crit.options[:fields] ||= {}
crit.options[:fields][:only] = args.flatten if args.any?
end
end
end
module Optional
# Adds a criterion to the +Criteria+ that specifies the maximum number of
# results to return. This is mostly used in conjunction with <tt>skip()</tt>
# to handle paginated results.
#
# Options:
#
# value: An +Integer+ specifying the max number of results. Defaults to 20.
# hash: A +Hash+ specifying the max number of results for the embedded collections.
#
# Example:
#
# <tt>criteria.limit(100)</tt>
# <tt>criteria.limit(100, { :contents => 5 })</tt>
# <tt>criteria.limit(:contents => 5)</tt>
#
# Returns: <tt>self</tt>
def limit(*args)
clone.tap do |crit|
arguments = args.first || 20
fields = nil # hash of embedded collections
case arguments
when Integer
crit.options[:limit] = arguments
fields = args[1] if args.size > 1
when Hash
fields = arguments
end
if fields
crit.options[:fields] ||= {}
crit.options[:fields][:limit] = fields
end
end
end
end
end
module Contexts #:nodoc:
class Mongo
# Filters the field list. If no fields have been supplied, then it will be
# empty. If fields have been defined then _type will be included as well.
def process_options
fields = options[:fields]
only = fields.delete(:only) if fields
limits = fields.delete(:limit) if fields
# only ?
if only && only.size > 0
only << :_type if !only.include?(:_type)
only.each do |field|
options[:fields].merge!(field => 1)
end
end
# limit for embedded collections ?
if limits && limits.size > 0
limits.each do |field, limit|
options[:fields][field] = { '$slice' => limit }
end
end
options.dup
end
end
end
end

View File

@ -40,7 +40,7 @@ Gem::Specification.new do |s|
s.add_dependency "heroku" s.add_dependency "heroku"
s.add_dependency "httparty", ">= 0.6.1" s.add_dependency "httparty", ">= 0.6.1"
s.add_dependency "RedCloth", "4.2.7" s.add_dependency "RedCloth", "4.2.7"
s.add_dependency "delayed_job", "2.1.2" s.add_dependency "delayed_job", "2.1.4"
s.add_dependency "delayed_job_mongoid", "1.0.2" s.add_dependency "delayed_job_mongoid", "1.0.2"
s.add_dependency "rubyzip" s.add_dependency "rubyzip"
s.add_dependency "locomotive_jammit-s3" s.add_dependency "locomotive_jammit-s3"

View File

@ -8,8 +8,7 @@
position: relative; position: relative;
top: -1px; top: -1px;
z-index: 998; z-index: 998;
min-height: 60px; height: 60px;
width: 950px;
margin: 0px; margin: 0px;
padding: 0 8px; padding: 0 8px;
background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0; background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0;
@ -25,24 +24,12 @@
border-top-right-radius: 3px ; border-top-right-radius: 3px ;
-moz-border-radius-top-right: 3px ; -moz-border-radius-top-right: 3px ;
-webkit-border-top-right-radius: 3px ; -webkit-border-top-right-radius: 3px ;
width: 826px; height: 60px; }
padding-right: 124px;
padding-top: 8px;
padding-bottom: 8px;
min-height: 44px; }
#submenu > ul:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden; }
#submenu > ul a { #submenu > ul a {
text-decoration: none; } text-decoration: none; }
#submenu > ul > li { #submenu > ul > li {
margin: 7px 7px 7px 8px; margin: 15px 7px 0 8px;
height: 30px; float: left; }
float: left;
position: relative; }
#submenu > ul > li.hoverable > a span em { #submenu > ul > li.hoverable > a span em {
display: inline-block; display: inline-block;
background: transparent url(/images/admin/menu/icons.png) no-repeat 0 -16px; background: transparent url(/images/admin/menu/icons.png) no-repeat 0 -16px;
@ -114,9 +101,10 @@
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 22px; right: 22px;
height: 100%; height: 60px;
padding-left: 20px; padding-left: 20px;
z-index: 1; } z-index: 1;
background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0; }
#submenu > .action a { #submenu > .action a {
margin-top: 18px; margin-top: 18px;
display: inline-block; display: inline-block;
@ -148,7 +136,7 @@
border-color: black; } border-color: black; }
#submenu .popup { #submenu .popup {
position: absolute; position: absolute;
top: 26px; top: 42px;
min-width: 250px; min-width: 250px;
background: #fff; background: #fff;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
@ -197,6 +185,7 @@
color: #8b8d9a; color: #8b8d9a;
font-size: 0.7em; } font-size: 0.7em; }
#submenu .popup ul.big-links { #submenu .popup ul.big-links {
list-style: none;
margin: 0px; } margin: 0px; }
#submenu .popup ul.big-links li { #submenu .popup ul.big-links li {
margin: 10px 0; } margin: 10px 0; }
@ -207,7 +196,7 @@
padding: 3px 10px; padding: 3px 10px;
background: #ebedf4; background: #ebedf4;
font-weight: bold; font-weight: bold;
font-size: 14px; } font-size: 0.8em; }
#submenu .popup .footer { #submenu .popup .footer {
background: #ebedf4; background: #ebedf4;
padding: 8px 16px; padding: 8px 16px;
@ -323,7 +312,7 @@ body.contents #submenu > ul {
background: -moz-linear-gradient(0% 100% 90deg, #212229, #1e1e24); background: -moz-linear-gradient(0% 100% 90deg, #212229, #1e1e24);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#1e1e24), to(#212229)); } background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#1e1e24), to(#212229)); }
body.contents #submenu > .action { body.contents #submenu > .action {
background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0; } background-image: url(/images/admin/menu/submenu/black-action-border.png) !important; }
#menu li.assets a em { #menu li.assets a em {
position: relative; position: relative;

View File

@ -9,8 +9,7 @@
position: relative; position: relative;
top: -1px; top: -1px;
z-index: 998; z-index: 998;
min-height: 60px; height: 60px;
width: 950px;
margin: 0px; margin: 0px;
padding: 0 8px; padding: 0 8px;
background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0; background: transparent url(/images/admin/menu/shadow.png) repeat-y 0 0;
@ -18,22 +17,16 @@
/* ___ submenu items ___ */ /* ___ submenu items ___ */
& > ul { & > ul {
@include clearfix;
@include reset; @include reset;
border-top: 1px solid rgba(255, 255, 255, 0.4); border-top: 1px solid rgba(255, 255, 255, 0.4);
background: transparent url(/images/admin/menu/submenu/shadow.png) repeat-x 0 0; background: transparent url(/images/admin/menu/submenu/shadow.png) repeat-x 0 0;
@include rounded(top-right, 3px); @include rounded(top-right, 3px);
width: 826px;
padding-right: 124px; height: 60px;
padding-top: 8px;
padding-bottom: 8px;
min-height: 44px;
& > li { & > li {
margin: 7px 7px 7px 8px; margin: 15px 7px 0 8px;
height: 30px;
float: left; float: left;
position: relative;
&.hoverable > a span { &.hoverable > a span {
em { em {
@ -112,9 +105,10 @@
& > .action { & > .action {
@include absolute-position(top, 0px, right, 22px); @include absolute-position(top, 0px, right, 22px);
height: 100%; height: 60px;
padding-left: 20px; padding-left: 20px;
z-index: 1; z-index: 1;
background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0;
a { a {
margin-top: 18px; margin-top: 18px;
@ -156,7 +150,7 @@
.popup { .popup {
position: absolute; position: absolute;
top: 26px; top: 42px;
min-width: 250px; min-width: 250px;
background: #fff; background: #fff;
@include box-shadow(0px, 0px, 10px, rgba(0, 0, 0, 0.5)); @include box-shadow(0px, 0px, 10px, rgba(0, 0, 0, 0.5));
@ -209,6 +203,7 @@
} }
&.big-links { &.big-links {
list-style: none;
margin: 0px; margin: 0px;
li { li {
@ -219,7 +214,7 @@
padding: 3px 10px; padding: 3px 10px;
background: #ebedf4; background: #ebedf4;
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 0.8em;
} }
} }
} }
@ -259,7 +254,7 @@
} }
& > .action { & > .action {
background: transparent url(/images/admin/menu/submenu/action-border.png) repeat-y left 0; background-image: url(/images/admin/menu/submenu/black-action-border.png) !important;
} }
} }