categories in content types have been improved a lot + cross-site session + meta keys / description for site + clean code + fix bugs
This commit is contained in:
parent
524ccc3613
commit
b7e1cd0926
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ rails_3_gems
|
|||||||
doc/performance.txt
|
doc/performance.txt
|
||||||
doc/production.sh
|
doc/production.sh
|
||||||
*.gem
|
*.gem
|
||||||
|
tmp/*
|
||||||
|
@ -6,7 +6,7 @@ module Admin
|
|||||||
before_filter :set_content_type
|
before_filter :set_content_type
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@contents = @content_type.ordered_contents
|
@contents = @content_type.list_or_group_contents
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@ -21,11 +21,10 @@ module Admin
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def new_host_if_subdomain_changed
|
def new_host_if_subdomain_changed
|
||||||
host_from_site = "#{@site.subdomain}.#{Locomotive.config.default_domain}"
|
if @site.domains.include?(request.host)
|
||||||
if request.host == host_from_site
|
|
||||||
{}
|
{}
|
||||||
else
|
else
|
||||||
{ :host => "#{host_from_site}:#{request.port}" }
|
{ :host => "#{@site.subdomain}.#{Locomotive.config.default_domain}:#{request.port}" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,16 +33,5 @@ module Admin
|
|||||||
redirect_to edit_admin_my_account_url
|
redirect_to edit_admin_my_account_url
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def new_host_if_subdomain_changed
|
|
||||||
host_from_site = "#{@site.subdomain}.#{Locomotive.config.default_domain}"
|
|
||||||
if request.host == host_from_site
|
|
||||||
{}
|
|
||||||
else
|
|
||||||
{ :host => "#{host_from_site}:#{request.port}" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -21,4 +21,11 @@ module Admin::CustomFieldsHelper
|
|||||||
collection.map { |field| [field.label, field._name] }
|
collection.map { |field| [field.label, field._name] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def options_for_group_by_field(content_type, collection_name)
|
||||||
|
custom_fields_collection_name = "ordered_#{collection_name.singularize}_custom_fields".to_sym
|
||||||
|
collection = content_type.send(custom_fields_collection_name)
|
||||||
|
collection.delete_if { |f| not f.category? }
|
||||||
|
collection.map { |field| [field.label, field._name] }
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -20,4 +20,14 @@ module Admin::PagesHelper
|
|||||||
list
|
list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def options_for_page_cache_expiration
|
||||||
|
[
|
||||||
|
[t('.expiration.never'), 0],
|
||||||
|
[t('.expiration.hour'), 1.hour],
|
||||||
|
[t('.expiration.day'), 1.day],
|
||||||
|
[t('.expiration.week'), 1.week],
|
||||||
|
[t('.expiration.month'), 1.month]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -15,6 +15,9 @@ class ContentInstance
|
|||||||
## associations ##
|
## associations ##
|
||||||
embedded_in :content_type, :inverse_of => :contents
|
embedded_in :content_type, :inverse_of => :contents
|
||||||
|
|
||||||
|
## callbacks ##
|
||||||
|
before_create :add_to_list_bottom
|
||||||
|
|
||||||
## 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
|
||||||
|
|
||||||
@ -26,6 +29,11 @@ class ContentInstance
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
|
def add_to_list_bottom
|
||||||
|
Rails.logger.debug "add_to_list_bottom"
|
||||||
|
self._position_in_list = self.content_type.contents.size
|
||||||
|
end
|
||||||
|
|
||||||
def require_highlighted_field
|
def require_highlighted_field
|
||||||
_alias = self.content_type.highlighted_field._alias.to_sym
|
_alias = self.content_type.highlighted_field._alias.to_sym
|
||||||
if self.send(_alias).blank?
|
if self.send(_alias).blank?
|
||||||
|
@ -8,6 +8,7 @@ class ContentType
|
|||||||
field :slug
|
field :slug
|
||||||
field :order_by
|
field :order_by
|
||||||
field :highlighted_field_name
|
field :highlighted_field_name
|
||||||
|
field :group_by_field_name
|
||||||
field :api_enabled, :type => Boolean, :default => false
|
field :api_enabled, :type => Boolean, :default => false
|
||||||
|
|
||||||
## associations ##
|
## associations ##
|
||||||
@ -28,6 +29,26 @@ class ContentType
|
|||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
|
||||||
|
def groupable?
|
||||||
|
self.group_by_field && group_by_field.category?
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_or_group_contents
|
||||||
|
if self.groupable?
|
||||||
|
groups = self.contents.klass.send(:"group_by_#{self.group_by_field._alias}", :ordered_contents)
|
||||||
|
|
||||||
|
# look for items with no category or unknown ones
|
||||||
|
items_without_category = self.contents.find_all { |c| !self.group_by_field.category_ids.include?(c.send(self.group_by_field_name)) }
|
||||||
|
if not items_without_category.empty?
|
||||||
|
groups << { :name => nil, :items => items_without_category }
|
||||||
|
else
|
||||||
|
groups
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.ordered_contents
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def ordered_contents(conditions = {})
|
def ordered_contents(conditions = {})
|
||||||
column = self.order_by.to_sym
|
column = self.order_by.to_sym
|
||||||
|
|
||||||
@ -49,6 +70,10 @@ class ContentType
|
|||||||
self.content_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
self.content_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def group_by_field
|
||||||
|
@group_by_field ||= self.content_custom_fields.detect { |f| f._name == self.group_by_field_name }
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def set_default_values
|
def set_default_values
|
||||||
|
@ -12,8 +12,7 @@ class Page
|
|||||||
field :slug
|
field :slug
|
||||||
field :fullpath
|
field :fullpath
|
||||||
field :published, :type => Boolean, :default => false
|
field :published, :type => Boolean, :default => false
|
||||||
field :keywords
|
field :cache_expires_in, :type => Integer, :default => 0
|
||||||
field :description
|
|
||||||
|
|
||||||
## associations ##
|
## associations ##
|
||||||
belongs_to_related :site
|
belongs_to_related :site
|
||||||
@ -36,6 +35,7 @@ class Page
|
|||||||
named_scope :not_found, :where => { :slug => '404', :depth => 0, :published => true }
|
named_scope :not_found, :where => { :slug => '404', :depth => 0, :published => true }
|
||||||
|
|
||||||
## behaviours ##
|
## behaviours ##
|
||||||
|
liquid_methods :title, :fullpath
|
||||||
liquify_template :joined_parts
|
liquify_template :joined_parts
|
||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
@ -6,6 +6,8 @@ class Site
|
|||||||
field :name
|
field :name
|
||||||
field :subdomain
|
field :subdomain
|
||||||
field :domains, :type => Array, :default => []
|
field :domains, :type => Array, :default => []
|
||||||
|
field :meta_keywords
|
||||||
|
field :meta_description
|
||||||
|
|
||||||
## associations ##
|
## associations ##
|
||||||
has_many_related :pages
|
has_many_related :pages
|
||||||
@ -33,7 +35,7 @@ class Site
|
|||||||
named_scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :_id.ne => site.id } } }
|
named_scope :match_domain_with_exclusion_of, lambda { |domain, site| { :where => { :domains => domain, :_id.ne => site.id } } }
|
||||||
|
|
||||||
## behaviours ##
|
## behaviours ##
|
||||||
liquid_methods :name
|
liquid_methods :name, :meta_keywords, :meta_description
|
||||||
|
|
||||||
## methods ##
|
## methods ##
|
||||||
|
|
||||||
|
@ -10,9 +10,13 @@
|
|||||||
= render 'admin/custom_fields/index', :f => f, :collection_name => 'contents'
|
= render 'admin/custom_fields/index', :f => f, :collection_name => 'contents'
|
||||||
|
|
||||||
- unless f.object.new_record?
|
- unless f.object.new_record?
|
||||||
= f.foldable_inputs :name => :options, :class => 'switchable' do
|
= f.foldable_inputs :name => :presentation, :class => 'switchable' do
|
||||||
= f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false
|
= f.input :highlighted_field_name, :as => :select, :collection => options_for_highlighted_field(f.object, 'contents'), :include_blank => false
|
||||||
|
= f.input :group_by_field_name, :as => :select, :collection => options_for_group_by_field(f.object, 'contents')
|
||||||
|
|
||||||
|
= f.foldable_inputs :name => :options, :class => 'switchable' do
|
||||||
= f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false
|
= f.input :order_by, :as => :select, :collection => options_for_order_by(f.object, 'contents'), :include_blank => false
|
||||||
= f.custom_input :api_enabled, :css => 'toggle' do
|
= f.custom_input :api_enabled, :css => 'toggle' do
|
||||||
= f.check_box :api_enabled
|
= f.check_box :api_enabled
|
||||||
|
|
||||||
|
|
||||||
|
16
app/views/admin/contents/_list.html.haml
Normal file
16
app/views/admin/contents/_list.html.haml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
- if contents.empty?
|
||||||
|
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
||||||
|
- else
|
||||||
|
- puts contents.inspect
|
||||||
|
%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}" }
|
||||||
|
%em
|
||||||
|
%strong
|
||||||
|
= link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content)
|
||||||
|
.more
|
||||||
|
%span
|
||||||
|
= t('admin.contents.index.updated_at')
|
||||||
|
= l content.updated_at, :format => :short rescue 'n/a'
|
||||||
|
|
||||||
|
= link_to image_tag('admin/list/icons/trash.png'), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
@ -13,21 +13,13 @@
|
|||||||
- if @content_type.description.present?
|
- if @content_type.description.present?
|
||||||
%p= @content_type.description
|
%p= @content_type.description
|
||||||
|
|
||||||
- if @contents.empty?
|
- if @content_type.groupable?
|
||||||
%p.no-items= t('.no_items', :url => new_admin_content_url(@content_type.slug))
|
- @contents.each do |group|
|
||||||
|
%h3= group[:name] || t('.category_noname')
|
||||||
|
= render 'list', :contents => group[:items]
|
||||||
|
%br
|
||||||
- else
|
- else
|
||||||
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}" }
|
= render 'list', :contents => @contents
|
||||||
- @contents.each do |content|
|
|
||||||
%li.content{ :id => "content-#{content._id}" }
|
|
||||||
%em
|
|
||||||
%strong
|
|
||||||
= link_to content.send(@content_type.highlighted_field_name), edit_admin_content_path(@content_type.slug, content)
|
|
||||||
.more
|
|
||||||
%span
|
|
||||||
= t('admin.contents.index.updated_at')
|
|
||||||
= l content.updated_at, :format => :short rescue 'n/a'
|
|
||||||
|
|
||||||
= link_to image_tag('admin/list/icons/trash.png'), admin_content_path(@content_type.slug, content), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
|
|
||||||
|
|
||||||
= form_tag sort_admin_contents_path(@content_type.slug), :method => :put, :class => 'formtastic' do
|
= form_tag sort_admin_contents_path(@content_type.slug), :method => :put, :class => 'formtastic' do
|
||||||
= hidden_field_tag :order
|
= hidden_field_tag :order
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
|
= f.foldable_inputs :name => :information, :style => "#{'display: none' unless @site.new_record?}" do
|
||||||
= f.input :name, :required => false
|
= f.input :name, :required => false
|
||||||
|
|
||||||
|
= f.foldable_inputs :name => :meta do
|
||||||
|
|
||||||
|
= f.input :meta_keywords
|
||||||
|
= f.input :meta_description
|
||||||
|
|
||||||
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
= f.foldable_inputs :name => :access_points, :class => 'editable-list off' do
|
||||||
|
|
||||||
= f.custom_input :subdomain, :css => 'path' do
|
= f.custom_input :subdomain, :css => 'path' do
|
||||||
|
@ -16,10 +16,7 @@
|
|||||||
= f.custom_input :published, :css => 'toggle' do
|
= f.custom_input :published, :css => 'toggle' do
|
||||||
= f.check_box :published
|
= f.check_box :published
|
||||||
|
|
||||||
= f.foldable_inputs :name => :meta do
|
= f.input :cache_expires_in, :as => :select, :collection => options_for_page_cache_expiration, :include_blank => false
|
||||||
|
|
||||||
= f.input :keywords
|
|
||||||
= f.input :description
|
|
||||||
|
|
||||||
#page-parts
|
#page-parts
|
||||||
.nav
|
.nav
|
||||||
|
@ -84,8 +84,16 @@ en:
|
|||||||
successful_create: "Page was successfully created."
|
successful_create: "Page was successfully created."
|
||||||
successful_update: "Page was successfully updated."
|
successful_update: "Page was successfully updated."
|
||||||
successful_destroy: "Page was successfully deleted."
|
successful_destroy: "Page was successfully deleted."
|
||||||
|
successful_sort: "Pages were successfully sorted."
|
||||||
failed_create: "Page was not created."
|
failed_create: "Page was not created."
|
||||||
failed_update: "Page was not updated."
|
failed_update: "Page was not updated."
|
||||||
|
form:
|
||||||
|
expiration:
|
||||||
|
never: Never
|
||||||
|
hour: 1 hour
|
||||||
|
day: 1 day
|
||||||
|
week: 1 week
|
||||||
|
month: 1 month
|
||||||
|
|
||||||
layouts:
|
layouts:
|
||||||
index:
|
index:
|
||||||
@ -265,9 +273,11 @@ en:
|
|||||||
destroy: remove model
|
destroy: remove model
|
||||||
download: download items
|
download: download items
|
||||||
new: new item
|
new: new item
|
||||||
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
category_noname: "No name"
|
||||||
lastest_items: "Lastest items"
|
lastest_items: "Lastest items"
|
||||||
updated_at: "Updated at"
|
updated_at: "Updated at"
|
||||||
|
list:
|
||||||
|
no_items: "There are no items for now. Just click <a href=\"{{url}}\">here</a> to create the first one."
|
||||||
new:
|
new:
|
||||||
title: '{{type}} — new item'
|
title: '{{type}} — new item'
|
||||||
edit:
|
edit:
|
||||||
@ -297,6 +307,7 @@ en:
|
|||||||
options: Advanced options
|
options: Advanced options
|
||||||
custom_fields: Custom fields
|
custom_fields: Custom fields
|
||||||
other_fields: Other information
|
other_fields: Other information
|
||||||
|
presentation: Presentation
|
||||||
labels:
|
labels:
|
||||||
theme_asset:
|
theme_asset:
|
||||||
new:
|
new:
|
||||||
@ -311,6 +322,8 @@ en:
|
|||||||
page:
|
page:
|
||||||
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||||
description: "Meta description used within the head tag of the page. Required for SEO."
|
description: "Meta description used within the head tag of the page. Required for SEO."
|
||||||
|
published: "Only authenticated accounts can view unpublished pages."
|
||||||
|
cache_expires_in: "Cache the page for better performance. Pressing shift-reload in the browser will regenerate the page."
|
||||||
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:
|
||||||
|
21
doc/TODO
21
doc/TODO
@ -1,7 +1,7 @@
|
|||||||
BOARD:
|
BOARD:
|
||||||
|
|
||||||
- deploy on Heroku
|
- new custom field types
|
||||||
- observers to add / remove domains (http://groups.google.com/group/heroku/browse_thread/thread/148d6ea68e4574fb/4d8f1c8545d52bda?lnk=gst&q=heroku+gem+api#4d8f1c8545d52bda)
|
- boolean
|
||||||
|
|
||||||
BACKLOG:
|
BACKLOG:
|
||||||
|
|
||||||
@ -13,16 +13,15 @@ BACKLOG:
|
|||||||
|
|
||||||
- theme assets: disable version if not image
|
- theme assets: disable version if not image
|
||||||
|
|
||||||
- new custom field types
|
- new custom field types:
|
||||||
- file
|
- file
|
||||||
- boolean
|
|
||||||
- date
|
- date
|
||||||
|
|
||||||
- refactoring admin crud (pages + layouts + snippets)
|
- refactoring admin crud (pages + layouts + snippets)
|
||||||
- refactor slugify method (use parameterize + create a module)
|
- refactor slugify method (use parameterize + create a module)
|
||||||
- cucumber features for admin pages
|
- cucumber features for admin pages
|
||||||
|
|
||||||
- Heroku / S3 / Worker
|
- tiny mce or similar for custom field text type.
|
||||||
|
|
||||||
BUGS:
|
BUGS:
|
||||||
|
|
||||||
@ -32,8 +31,8 @@ NICE TO HAVE:
|
|||||||
- asset collections: custom resizing if image
|
- asset collections: custom resizing if image
|
||||||
- super_finder
|
- super_finder
|
||||||
- better icons for mime type
|
- better icons for mime type
|
||||||
- hint for custom fields (super easy to do !)
|
- traffic statistics
|
||||||
- tiny mce or similar for custom field text type.
|
- Heroku / S3 / Worker (not so sure finally)
|
||||||
|
|
||||||
DONE:
|
DONE:
|
||||||
x admin layout
|
x admin layout
|
||||||
@ -134,3 +133,11 @@ x site subdomain regexp [a-z][A-Z][0-9]
|
|||||||
x [BUG] "field name" for alias / hint for custom fields
|
x [BUG] "field name" for alias / hint for custom fields
|
||||||
x [BUG] can not remove custom fields at creation if object is invalid
|
x [BUG] can not remove custom fields at creation if object is invalid
|
||||||
x internal logger
|
x internal logger
|
||||||
|
x deploy on Heroku
|
||||||
|
x observers to add / remove domains (http://groups.google.com/group/heroku/browse_thread/thread/148d6ea68e4574fb/4d8f1c8545d52bda?lnk=gst&q=heroku+gem+api#4d8f1c8545d52bda)
|
||||||
|
x varnish caching (only with Heroku ?)
|
||||||
|
x page not included in liquid templates
|
||||||
|
x redirect to referer url when updating site
|
||||||
|
x [BUG] items non sorted in a category
|
||||||
|
x contents grouped by "category" in the admin
|
||||||
|
x hint for custom fields (super easy to do !)
|
@ -32,10 +32,9 @@ module Locomotive
|
|||||||
|
|
||||||
ActionMailer::Base.default_url_options[:host] = self.config.default_domain + (Rails.env.development? ? ':3000' : '')
|
ActionMailer::Base.default_url_options[:host] = self.config.default_domain + (Rails.env.development? ? ':3000' : '')
|
||||||
|
|
||||||
# cookies stored in mongodb
|
# cookies stored in mongodb (mongoid_store)
|
||||||
Rails.application.config.session_store :mongoid_store, {
|
Rails.application.config.session_store :mongoid_store, {
|
||||||
:key => Locomotive.config.cookie_key,
|
:key => Locomotive.config.cookie_key
|
||||||
:domain => ".#{Locomotive.config.default_domain}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Heroku support
|
# Heroku support
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
Devise::SessionsController.class_eval do
|
|
||||||
end
|
|
@ -53,9 +53,13 @@ module Locomotive
|
|||||||
|
|
||||||
def before_method(meth)
|
def before_method(meth)
|
||||||
klass = @content_type.contents.klass # delegate to the proxy class
|
klass = @content_type.contents.klass # delegate to the proxy class
|
||||||
|
if (meth.to_s =~ /^group_by_.+$/) == 0
|
||||||
|
klass.send(meth, :ordered_contents)
|
||||||
|
else
|
||||||
klass.send(meth)
|
klass.send(meth)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
@ -1,2 +1 @@
|
|||||||
# load patches for devise, ...etc
|
# load patches here
|
||||||
require 'locomotive/devise/sessions_controller'
|
|
@ -8,13 +8,13 @@ module Locomotive
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def render_locomotive_page
|
def render_locomotive_page
|
||||||
page = locomotive_page
|
@page = locomotive_page
|
||||||
|
|
||||||
redirect_to application_root_url and return if page.nil?
|
redirect_to application_root_url and return if @page.nil?
|
||||||
|
|
||||||
output = page.render(locomotive_context)
|
output = @page.render(locomotive_context)
|
||||||
|
|
||||||
prepare_and_set_response(output)
|
prepare_and_set_response(output, @page.cache_expires_in || 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
def locomotive_page
|
def locomotive_page
|
||||||
@ -35,6 +35,7 @@ module Locomotive
|
|||||||
def locomotive_context
|
def locomotive_context
|
||||||
assigns = {
|
assigns = {
|
||||||
'site' => current_site,
|
'site' => current_site,
|
||||||
|
'page' => @page,
|
||||||
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new(current_site),
|
'asset_collections' => Locomotive::Liquid::Drops::AssetCollections.new(current_site),
|
||||||
'stylesheets' => Locomotive::Liquid::Drops::Stylesheets.new(current_site),
|
'stylesheets' => Locomotive::Liquid::Drops::Stylesheets.new(current_site),
|
||||||
'javascripts' => Locomotive::Liquid::Drops::Javascripts.new(current_site),
|
'javascripts' => Locomotive::Liquid::Drops::Javascripts.new(current_site),
|
||||||
@ -42,13 +43,14 @@ module Locomotive
|
|||||||
'current_page' => self.params[:page]
|
'current_page' => self.params[:page]
|
||||||
}
|
}
|
||||||
|
|
||||||
registers = { :controller => self, :site => current_site }
|
registers = { :controller => self, :site => current_site, :page => @page }
|
||||||
|
|
||||||
::Liquid::Context.new(assigns, registers)
|
::Liquid::Context.new(assigns, registers)
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare_and_set_response(output)
|
def prepare_and_set_response(output, cache_expiration = 0)
|
||||||
response.headers["Content-Type"] = 'text/html; charset=utf-8'
|
response.headers['Cache-Control'] = "public, max-age=#{cache_expiration}" if cache_expiration > 0
|
||||||
|
response.headers['Content-Type'] = 'text/html; charset=utf-8'
|
||||||
render :text => output, :layout => false, :status => :ok
|
render :text => output, :layout => false, :status => :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
|
|
||||||
module Routing
|
module Routing
|
||||||
|
|
||||||
class DefaultConstraint
|
class DefaultConstraint
|
||||||
|
|
||||||
def self.matches?(request)
|
def self.matches?(request)
|
||||||
domain, subdomain = domain_and_subdomain(request)
|
domain, subdomain = domain_and_subdomain(request)
|
||||||
subdomain = 'www' if subdomain.blank?
|
subdomain = 'www' if subdomain.blank?
|
||||||
|
|
||||||
# puts "domain = #{domain} / #{Locomotive.config.default_domain.inspect}"
|
|
||||||
# puts "subdomain = #{subdomain} / #{Locomotive.config.reserved_subdomains.inspect}"
|
|
||||||
|
|
||||||
domain == Locomotive.config.default_domain && Locomotive.config.reserved_subdomains.include?(subdomain)
|
domain == Locomotive.config.default_domain && Locomotive.config.reserved_subdomains.include?(subdomain)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -38,8 +33,7 @@ module Locomotive
|
|||||||
parts = request.host.split('.')
|
parts = request.host.split('.')
|
||||||
parts[0..-(tld_length+2)]
|
parts[0..-(tld_length+2)]
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
@ -1,18 +1,14 @@
|
|||||||
module Locomotive
|
module Locomotive
|
||||||
|
|
||||||
module Routing
|
module Routing
|
||||||
|
|
||||||
module SiteDispatcher
|
module SiteDispatcher
|
||||||
|
|
||||||
def self.included(base)
|
extend ActiveSupport::Concern
|
||||||
base.class_eval do
|
|
||||||
include Locomotive::Routing::SiteDispatcher::InstanceMethods
|
|
||||||
|
|
||||||
|
included do
|
||||||
before_filter :fetch_site
|
before_filter :fetch_site
|
||||||
|
|
||||||
helper_method :current_site
|
helper_method :current_site
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
module InstanceMethods
|
module InstanceMethods
|
||||||
|
|
||||||
@ -43,7 +39,5 @@ module Locomotive
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -1,9 +1,11 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
var updateContentsOrder = function() {
|
var updateContentsOrder = function() {
|
||||||
var list = $('ul#contents-list.sortable');
|
var lists = $('ul#contents-list.sortable');
|
||||||
var ids = jQuery.map(list.sortable('toArray'), function(e) {
|
var ids = jQuery.map(lists, function(list) {
|
||||||
return e.match(/content-(\w+)/)[1];
|
return(jQuery.map($(list).sortable('toArray'), function(el) {
|
||||||
|
return el.match(/content-(\w+)/)[1];
|
||||||
|
}).join(','));
|
||||||
}).join(',');
|
}).join(',');
|
||||||
$('#order').val(ids || '');
|
$('#order').val(ids || '');
|
||||||
}
|
}
|
||||||
|
33
spec/lib/locomotive/liquid/drops/contents_spec.rb
Normal file
33
spec/lib/locomotive/liquid/drops/contents_spec.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Locomotive::Liquid::Drops::Contents do
|
||||||
|
|
||||||
|
before(:each) do
|
||||||
|
@site = Factory.build(:site)
|
||||||
|
@content_type = Factory.build(:content_type, :site => @site, :slug => 'projects')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'retrieves a content type from a slug' do
|
||||||
|
@site.content_types.expects(:where).with(:slug => 'projects')
|
||||||
|
render_template '{{ contents.projects }}'
|
||||||
|
end
|
||||||
|
|
||||||
|
context '#group_by' do
|
||||||
|
|
||||||
|
it 'orders contents' do
|
||||||
|
@site.content_types.stubs(:where).returns([@content_type])
|
||||||
|
@content_type.contents.klass.expects(:group_by_category).with(:ordered_contents)
|
||||||
|
render_template '{% for group in contents.projects.group_by_category %} {{ group.name }} {% endfor %}'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_template(template = '', assigns = {})
|
||||||
|
assigns = {
|
||||||
|
'contents' => Locomotive::Liquid::Drops::Contents.new(@site)
|
||||||
|
}.merge(assigns)
|
||||||
|
|
||||||
|
Liquid::Template.parse(template).render assigns
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -16,14 +16,23 @@ describe 'Locomotive rendering system' do
|
|||||||
@controller.send(:prepare_and_set_response, 'Hello world !')
|
@controller.send(:prepare_and_set_response, 'Hello world !')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should have a html content type' do
|
it 'sets the content type to html' do
|
||||||
@controller.response.headers["Content-Type"].should == 'text/html; charset=utf-8'
|
@controller.response.headers['Content-Type'].should == 'text/html; charset=utf-8'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should display the output' do
|
it 'displays the output' do
|
||||||
@controller.output.should == 'Hello world !'
|
@controller.output.should == 'Hello world !'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not set the cache' do
|
||||||
|
@controller.response.headers['Cache-Control'].should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets the cache' do
|
||||||
|
@controller.send(:prepare_and_set_response, 'Hello world !', 3600)
|
||||||
|
@controller.response.headers['Cache-Control'].should == 'public, max-age=3600'
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when retrieving page' do
|
context 'when retrieving page' do
|
||||||
|
2
vendor/plugins/custom_fields/Gemfile
vendored
2
vendor/plugins/custom_fields/Gemfile
vendored
@ -3,7 +3,7 @@ source "http://gemcutter.org"
|
|||||||
gem "bson_ext", ">= 1.0.1"
|
gem "bson_ext", ">= 1.0.1"
|
||||||
gem "mongo_ext"
|
gem "mongo_ext"
|
||||||
gem "mongoid", ">= 2.0.0.beta6"
|
gem "mongoid", ">= 2.0.0.beta6"
|
||||||
gem "activesupport", ">= 3.0.0.beta4"
|
gem "activesupport", ">= 3.0.0.beta3"
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'rspec', '>= 2.0.0.beta.10'
|
gem 'rspec', '>= 2.0.0.beta.10'
|
||||||
|
@ -18,6 +18,14 @@ module CustomFields
|
|||||||
self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
self.category_items.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def category_names
|
||||||
|
self.category_items.collect(&:name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def category_ids
|
||||||
|
self.category_items.collect(&:_id)
|
||||||
|
end
|
||||||
|
|
||||||
def apply_category_type(klass)
|
def apply_category_type(klass)
|
||||||
klass.cattr_accessor :"#{self.safe_alias}_items"
|
klass.cattr_accessor :"#{self.safe_alias}_items"
|
||||||
|
|
||||||
@ -28,11 +36,13 @@ module CustomFields
|
|||||||
self.#{self.safe_alias}_items.collect(&:name)
|
self.#{self.safe_alias}_items.collect(&:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.group_by_#{self.safe_alias}
|
def self.group_by_#{self.safe_alias}(list_method = nil)
|
||||||
groups = (if self.embedded?
|
groups = (if self.embedded?
|
||||||
self._parent.send(self.association_name).all
|
list_method ||= self.association_name
|
||||||
|
self._parent.send(list_method)
|
||||||
else
|
else
|
||||||
self.all
|
list_method ||= :all
|
||||||
|
self.send(list_method)
|
||||||
end).to_a.group_by(&:#{self._name})
|
end).to_a.group_by(&:#{self._name})
|
||||||
|
|
||||||
self.#{self.safe_alias}_items.collect do |category|
|
self.#{self.safe_alias}_items.collect do |category|
|
||||||
|
@ -13,4 +13,6 @@ class Project
|
|||||||
custom_fields_for :people
|
custom_fields_for :people
|
||||||
custom_fields_for :tasks
|
custom_fields_for :tasks
|
||||||
|
|
||||||
|
named_scope :ordered, :order_by => [[:name, :asc]]
|
||||||
|
|
||||||
end
|
end
|
@ -67,6 +67,11 @@ describe CustomFields::Types::Category do
|
|||||||
@groups[2][:items].size.should == 2
|
@groups[2][:items].size.should == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'passes method to retrieve items' do
|
||||||
|
@project.class.expects(:ordered)
|
||||||
|
@project.class.group_by_global_category(:ordered)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user