Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
35d5e7d44e
6
Gemfile
6
Gemfile
@ -2,12 +2,12 @@ source :rubygems
|
||||
|
||||
# add in all the runtime dependencies
|
||||
|
||||
gem 'rails', '>= 3.0.5'
|
||||
gem 'rails', '>= 3.0.7'
|
||||
|
||||
gem 'warden'
|
||||
gem 'devise', '= 1.1.3'
|
||||
|
||||
gem 'mongoid', '2.0.0.rc.7'
|
||||
gem 'mongoid', '~> 2.0.1'
|
||||
gem 'bson_ext', '~> 1.3.0'
|
||||
gem 'locomotive_mongoid_acts_as_tree', '0.1.5.5', :require => 'mongoid_acts_as_tree'
|
||||
gem 'will_paginate'
|
||||
@ -20,7 +20,7 @@ gem 'inherited_resources', '~> 1.1.2'
|
||||
gem 'rmagick', '2.12.2'
|
||||
gem 'locomotive_carrierwave', '0.5.0.1.beta3', :require => 'carrierwave'
|
||||
|
||||
gem 'custom_fields', '1.0.0.beta.10'
|
||||
gem 'custom_fields', '1.0.0.beta.12'
|
||||
gem 'fog', '0.3.7'
|
||||
gem 'mimetype-fu'
|
||||
gem 'actionmailer-with-request', :require => 'actionmailer_with_request'
|
||||
|
39
Gemfile.lock
39
Gemfile.lock
@ -1,6 +1,6 @@
|
||||
GIT
|
||||
remote: git://github.com/floehopper/mocha.git
|
||||
revision: 6fe08197f214457ac122c49d96fdac8e17adbea2
|
||||
revision: 7dd9512a874f89b8037d7320fe7988c222f439e1
|
||||
specs:
|
||||
mocha (0.9.12.20110213002255)
|
||||
|
||||
@ -51,12 +51,12 @@ GEM
|
||||
activesupport (= 3.0.7)
|
||||
activesupport (3.0.7)
|
||||
archive-tar-minitar (0.5.2)
|
||||
arel (2.0.9)
|
||||
arel (2.0.10)
|
||||
autotest (4.4.6)
|
||||
ZenTest (>= 4.4.1)
|
||||
bcrypt-ruby (2.1.4)
|
||||
bson (1.3.0)
|
||||
bson_ext (1.3.0)
|
||||
bson (1.3.1)
|
||||
bson_ext (1.3.1)
|
||||
builder (2.1.2)
|
||||
bushido (0.0.12)
|
||||
highline (>= 1.6.1)
|
||||
@ -72,7 +72,7 @@ GEM
|
||||
selenium-webdriver (>= 0.0.27)
|
||||
xpath (~> 0.1.2)
|
||||
celerity (0.8.9)
|
||||
childprocess (0.1.8)
|
||||
childprocess (0.1.9)
|
||||
ffi (~> 1.0.6)
|
||||
closure-compiler (1.1.1)
|
||||
columnize (0.3.2)
|
||||
@ -87,10 +87,10 @@ GEM
|
||||
cucumber-rails (0.3.2)
|
||||
cucumber (>= 0.8.0)
|
||||
culerity (0.2.15)
|
||||
custom_fields (1.0.0.beta.10)
|
||||
activesupport (>= 3.0.4)
|
||||
custom_fields (1.0.0.beta.12)
|
||||
activesupport (>= 3.0.7)
|
||||
locomotive_carrierwave
|
||||
mongoid (~> 2.0.0.rc.7)
|
||||
mongoid (~> 2.0.1)
|
||||
daemons (1.1.3)
|
||||
database_cleaner (0.6.7)
|
||||
delayed_job (2.1.4)
|
||||
@ -110,8 +110,7 @@ GEM
|
||||
factory_girl_rails (1.0.1)
|
||||
factory_girl (~> 1.3)
|
||||
railties (>= 3.0.0)
|
||||
ffi (1.0.7)
|
||||
rake (>= 0.8.7)
|
||||
ffi (1.0.8)
|
||||
fog (0.3.7)
|
||||
builder
|
||||
excon (>= 0.2.3)
|
||||
@ -134,8 +133,8 @@ GEM
|
||||
heroku (1.19.1)
|
||||
activesupport (>= 2.1.0)
|
||||
launchy (~> 0.3.2)
|
||||
rest-client (>= 1.4.0, < 1.7.0)
|
||||
highline (1.6.1)
|
||||
rest-client (< 1.7.0, >= 1.4.0)
|
||||
highline (1.6.2)
|
||||
httparty (0.7.7)
|
||||
crack (= 0.1.8)
|
||||
i18n (0.5.0)
|
||||
@ -171,11 +170,11 @@ GEM
|
||||
mime-types (1.16)
|
||||
mimemagic (0.1.8)
|
||||
mimetype-fu (0.1.2)
|
||||
mongo (1.3.0)
|
||||
bson (>= 1.3.0)
|
||||
mongoid (2.0.0.rc.7)
|
||||
mongo (1.3.1)
|
||||
bson (>= 1.3.1)
|
||||
mongoid (2.0.1)
|
||||
activemodel (~> 3.0)
|
||||
mongo (~> 1.2)
|
||||
mongo (~> 1.3)
|
||||
tzinfo (~> 0.3.22)
|
||||
will_paginate (~> 3.0.pre)
|
||||
net-ssh (2.0.24)
|
||||
@ -205,7 +204,7 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
thor (~> 0.14.4)
|
||||
rake (0.8.7)
|
||||
responders (0.6.2)
|
||||
responders (0.6.4)
|
||||
rest-client (1.6.1)
|
||||
mime-types (>= 1.16)
|
||||
rmagick (2.12.2)
|
||||
@ -276,7 +275,7 @@ DEPENDENCIES
|
||||
capybara
|
||||
cucumber (= 0.8.5)
|
||||
cucumber-rails
|
||||
custom_fields (= 1.0.0.beta.10)
|
||||
custom_fields (= 1.0.0.beta.12)
|
||||
database_cleaner
|
||||
delayed_job (= 2.1.4)
|
||||
delayed_job_mongoid (= 1.0.2)
|
||||
@ -296,9 +295,9 @@ DEPENDENCIES
|
||||
locomotive_mongoid_acts_as_tree (= 0.1.5.5)
|
||||
mimetype-fu
|
||||
mocha!
|
||||
mongoid (= 2.0.0.rc.7)
|
||||
mongoid (~> 2.0.1)
|
||||
pickle
|
||||
rails (>= 3.0.5)
|
||||
rails (>= 3.0.7)
|
||||
rmagick (= 2.12.2)
|
||||
rspec-rails (= 2.3.1)
|
||||
ruby-debug
|
||||
|
@ -19,8 +19,8 @@ h2. Gems
|
||||
|
||||
Here is a short list of main gems used in the application.
|
||||
|
||||
* Rails 3.0.5
|
||||
* Mongoid 2.0.0.rc.7 (with MongoDB 1.6)
|
||||
* Rails 3.0.7
|
||||
* Mongoid 2.0.1 (with MongoDB 1.6)
|
||||
* Liquid
|
||||
* Devise
|
||||
* Carrierwave
|
||||
@ -38,6 +38,10 @@ h2. Team
|
||||
* Contributors: "Dirk Kelly":http://www.dirkkelly.com, "Mario Visic":http://www.mariovisic.com, "Raphael Costa":http://raphaelcosta.net (Brazilian Portuguese translation), "Bernd Hauser":http://www.designhunger.de (German translation), "Andrea Frigido":http://www.frisoft.it (Italian translation)
|
||||
* UI Designer: "Sacha Greif":http://www.sachagreif.com
|
||||
|
||||
h2. Support
|
||||
|
||||
Bernd Hauser from "designhunger":http://www.designhunger.de funded the following feature: *has_one* / *has_many* between content types.
|
||||
|
||||
h2. Credits
|
||||
|
||||
"Rodrigo Alvarez":http://blog.codecaster.es/ for his plugin named Congo which gave us a good starting point and for his availability for (very late) tech discussions.
|
||||
|
@ -7,7 +7,7 @@ module Admin::ContentTypesHelper
|
||||
|
||||
@content_types = current_site.content_types.ordered.
|
||||
limit(:contents => Locomotive.config.lastest_items_nb).
|
||||
only(:name, :slug, :highlighted_field_name, :content_custom_fields_version).to_a
|
||||
only(:name, :slug, :highlighted_field_name, :content_custom_fields_version, :order_by).to_a
|
||||
|
||||
if @content_type && @content_type.persisted? && @content_types.index(@content_type) >= MAX_DISPLAYED_CONTENTS
|
||||
@content_types.delete(@content_type)
|
||||
|
@ -1,7 +1,7 @@
|
||||
module Admin::CustomFieldsHelper
|
||||
|
||||
def options_for_field_kind
|
||||
%w(string text category boolean date file).map do |kind|
|
||||
%w(string text category boolean date file has_one has_many).map do |kind|
|
||||
[t("custom_fields.kind.#{kind}"), kind]
|
||||
end
|
||||
end
|
||||
@ -39,4 +39,19 @@ module Admin::CustomFieldsHelper
|
||||
end
|
||||
end
|
||||
|
||||
def options_for_association_target
|
||||
current_site.content_types.collect { |c| [c.name, c.content_klass.to_s] }
|
||||
end
|
||||
|
||||
def options_for_has_one(field)
|
||||
target_contents_from_field(field).collect { |c| [c._label, c._id] }
|
||||
end
|
||||
|
||||
alias :options_for_has_many :options_for_has_one
|
||||
|
||||
def target_contents_from_field(field)
|
||||
content_type = field.target.constantize._parent
|
||||
content_type.ordered_contents
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -5,6 +5,7 @@ class ContentInstance
|
||||
|
||||
## extensions ##
|
||||
include CustomFields::ProxyClassEnabler
|
||||
include Extensions::Shared::Seo
|
||||
|
||||
## fields (dynamic fields) ##
|
||||
field :_slug
|
||||
@ -29,6 +30,8 @@ class ContentInstance
|
||||
|
||||
## methods ##
|
||||
|
||||
delegate :site, :to => :content_type
|
||||
|
||||
alias :visible? :_visible?
|
||||
alias :_permalink :_slug
|
||||
|
||||
@ -37,9 +40,11 @@ class ContentInstance
|
||||
end
|
||||
|
||||
def highlighted_field_value
|
||||
self.send(self.content_type.highlighted_field._name)
|
||||
self.send(self.content_type.highlighted_field_name)
|
||||
end
|
||||
|
||||
alias :_label :highlighted_field_value
|
||||
|
||||
def visible?
|
||||
self._visible || self._visible.nil?
|
||||
end
|
||||
@ -48,6 +53,14 @@ class ContentInstance
|
||||
Hash.new.replace(self.errors)
|
||||
end
|
||||
|
||||
def reload_parent!
|
||||
self.class.reload_parent!
|
||||
end
|
||||
|
||||
def self.reload_parent!
|
||||
self._parent = self._parent.reload
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
Locomotive::Liquid::Drops::Content.new(self)
|
||||
end
|
||||
|
13
app/models/extensions/shared/seo.rb
Normal file
13
app/models/extensions/shared/seo.rb
Normal file
@ -0,0 +1,13 @@
|
||||
module Extensions
|
||||
module Shared
|
||||
module Seo
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
field :meta_keywords, :type => String
|
||||
field :meta_description, :type => String
|
||||
end
|
||||
|
||||
end # Seo
|
||||
end # Shared
|
||||
end # Extensions
|
@ -6,7 +6,7 @@ class Membership
|
||||
field :admin, :type => Boolean, :default => false
|
||||
|
||||
## associations ##
|
||||
referenced_in :account
|
||||
referenced_in :account, :validate => false
|
||||
embedded_in :site, :inverse_of => :memberships
|
||||
|
||||
## validations ##
|
||||
|
@ -10,6 +10,7 @@ class Page
|
||||
include Extensions::Page::Templatized
|
||||
include Extensions::Page::Redirect
|
||||
include Extensions::Page::Listed
|
||||
include Extensions::Shared::Seo
|
||||
|
||||
## fields ##
|
||||
field :title
|
||||
|
@ -2,4 +2,9 @@
|
||||
= include_javascripts :edit_custom_fields, :contents
|
||||
= include_stylesheets :fancybox
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
= render 'admin/custom_fields/custom_form', :form => f, :title => :attributes, :parent => @content_type
|
@ -4,35 +4,6 @@
|
||||
- form.object.custom_fields.each do |field|
|
||||
- required = highlighted_field_name == field._name || field.required
|
||||
|
||||
- if field.string?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :required => required
|
||||
|
||||
- elsif field.text?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :as => :text, :required => required, :input_html => { :class => field.text_formatting }
|
||||
|
||||
- elsif field.category?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.select field._name.to_sym, field.ordered_category_items.collect { |item| [item.name, item.id] }
|
||||
%button.button.light.edit-categories-link{ :type => 'button', :'data-url' => edit_admin_custom_field_path(parent.class.model_name.underscore, parent.slug, field) }
|
||||
%span!= t('.edit_categories')
|
||||
|
||||
- elsif field.boolean?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.check_box field._alias.to_sym
|
||||
|
||||
- elsif field.date?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'date' }
|
||||
|
||||
- elsif field.file?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'file' do
|
||||
= form.file_field field._name.to_sym
|
||||
- if form.object.send(:"#{field._name}?")
|
||||
%p.remove
|
||||
%strong
|
||||
= link_to File.basename(form.object.send(field._name).url), form.object.send(field._name).url
|
||||
%span
|
||||
/
|
||||
!= t('.delete_file')
|
||||
= form.check_box :"remove_#{field._name}"
|
||||
= render "/admin/custom_fields/types/#{field.kind}", :form => form, :parent => parent, :field => field, :required => required
|
||||
|
||||
= render '/admin/custom_fields/category_tmpl'
|
@ -8,6 +8,7 @@
|
||||
= g.input :_alias
|
||||
= g.input :hint
|
||||
= g.input :text_formatting, :as => 'select', :collection => options_for_text_formatting, :include_blank => false, :wrapper_html => { :style => 'display: none' }
|
||||
= g.input :target, :as => 'select', :collection => options_for_association_target, :include_blank => false, :wrapper_html => { :style => 'display: none' }
|
||||
|
||||
.popup-actions
|
||||
%p
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
%input{ :name => '{{base_name}}[text_formatting]', :value => '{{{text_formatting}}}', :type => 'hidden', :'data-field' => 'text_formatting' }
|
||||
|
||||
%input{ :name => '{{base_name}}[target]', :value => '{{{target}}}', :type => 'hidden', :'data-field' => 'target' }
|
||||
|
||||
%input{ :name => '{{base_name}}[label]', :value => '{{{label}}}', :type => 'text', :'data-field' => 'label' }
|
||||
|
||||
—
|
||||
|
2
app/views/admin/custom_fields/types/_boolean.html.haml
Normal file
2
app/views/admin/custom_fields/types/_boolean.html.haml
Normal file
@ -0,0 +1,2 @@
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.check_box field._alias.to_sym
|
4
app/views/admin/custom_fields/types/_category.html.haml
Normal file
4
app/views/admin/custom_fields/types/_category.html.haml
Normal file
@ -0,0 +1,4 @@
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.select field._name.to_sym, field.ordered_category_items.collect { |item| [item.name, item.id] }
|
||||
%button.button.light.edit-categories-link{ :type => 'button', :'data-url' => edit_admin_custom_field_path(parent.class.model_name.underscore, parent.slug, field) }
|
||||
%span!= t('.edit_categories')
|
1
app/views/admin/custom_fields/types/_date.html.haml
Normal file
1
app/views/admin/custom_fields/types/_date.html.haml
Normal file
@ -0,0 +1 @@
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'date' }
|
10
app/views/admin/custom_fields/types/_file.html.haml
Normal file
10
app/views/admin/custom_fields/types/_file.html.haml
Normal file
@ -0,0 +1,10 @@
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'file' do
|
||||
= form.file_field field._name.to_sym
|
||||
- if form.object.send(:"#{field._name}?")
|
||||
%p.remove
|
||||
%strong
|
||||
= link_to File.basename(form.object.send(field._name).url), form.object.send(field._name).url
|
||||
%span
|
||||
/
|
||||
!= t('.delete_file')
|
||||
= form.check_box :"remove_#{field._name}"
|
33
app/views/admin/custom_fields/types/_has_many.html.haml
Normal file
33
app/views/admin/custom_fields/types/_has_many.html.haml
Normal file
@ -0,0 +1,33 @@
|
||||
- field.target.constantize.reload_parent! # to make sure all the contents from the parent are loaded
|
||||
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'has-many' do
|
||||
|
||||
.has-many-selector
|
||||
|
||||
%p{ :style => form.object.send(field._alias.to_sym).empty? ? '' : 'display: none' }
|
||||
= t('.empty')
|
||||
|
||||
%ul
|
||||
|
||||
%script{ :type => 'text/x-mustache-template', :name => 'template', :'data-base-input-name' => "content[#{field._alias.to_sym}]" }
|
||||
%li{ :class => "item {{behaviour_flag}}" }
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
{{^if_template}}
|
||||
%input{ :name => '{{base_name}}[]', :value => '{{{id}}}', :type => 'hidden', :'data-field' => 'id' }
|
||||
{{/if_template}}
|
||||
|
||||
%strong {{label}}
|
||||
|
||||
{{#if_template}}
|
||||
= select_tag 'label', ''
|
||||
{{/if_template}}
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove'
|
||||
%button{ :class => 'button light mini add', :type => 'button' }
|
||||
%span!= t('admin.buttons.new_item')
|
||||
|
||||
%script{ :type => 'text/javascript', :name => 'data' }
|
||||
!= collection_to_js(options_for_has_many(field), :taken_ids => form.object.send(field._alias.to_sym).ids)
|
4
app/views/admin/custom_fields/types/_has_one.html.haml
Normal file
4
app/views/admin/custom_fields/types/_has_one.html.haml
Normal file
@ -0,0 +1,4 @@
|
||||
- field.target.constantize.reload_parent! # to make sure all the contents from the parent are loaded
|
||||
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'has_one' }, :as => :select, :collection => options_for_has_one(field), :selected => form.object.send(field._alias.to_sym).try(:_id)
|
||||
|
1
app/views/admin/custom_fields/types/_string.html.haml
Normal file
1
app/views/admin/custom_fields/types/_string.html.haml
Normal file
@ -0,0 +1 @@
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :required => required
|
1
app/views/admin/custom_fields/types/_text.html.haml
Normal file
1
app/views/admin/custom_fields/types/_text.html.haml
Normal file
@ -0,0 +1 @@
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :as => :text, :required => required, :input_html => { :class => field.text_formatting }
|
@ -11,6 +11,10 @@
|
||||
|
||||
= f.input :slug, :required => false, :hint => @page.slug.blank? ? ' ' : page_url(@page), :input_html => { :data_url => get_path_admin_pages_url, :disabled => @page.index? || @page.not_found? }, :wrapper_html => { :style => "#{'display: none' if @page.templatized?}; height: 50px" }
|
||||
|
||||
= f.foldable_inputs :name => :meta do
|
||||
|
||||
= f.input :meta_keywords
|
||||
= f.input :meta_description
|
||||
|
||||
= f.foldable_inputs :name => :advanced_options do
|
||||
|
||||
|
@ -34,6 +34,7 @@ javascripts:
|
||||
- public/javascripts/admin/plugins/fancybox.js
|
||||
- public/javascripts/admin/plugins/mustache.js
|
||||
- public/javascripts/admin/custom_fields/category.js
|
||||
- public/javascripts/admin/custom_fields/has_many.js
|
||||
asset_collections:
|
||||
- public/javascripts/admin/plugins/fancybox.js
|
||||
- public/javascripts/admin/plugins/mustache.js
|
||||
|
@ -50,10 +50,12 @@ en:
|
||||
templatized: "Use the page as a template for a model you defined."
|
||||
listed: "Control whether to show the page from generated menus."
|
||||
content_type_id: "The type of content this page will be a template for."
|
||||
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."
|
||||
meta_description: "Overrides the site's meta description used within the head tag of the page."
|
||||
snippet:
|
||||
slug: "You need to know it in order to insert the snippet inside a page"
|
||||
site:
|
||||
meta_keywords: "Meta keywords used within the head tag of the page. They are separeted by an empty space. Required for SEO."
|
||||
meta_keywords: "Meta keywords used within the head tag of the page. They are separated by a comma. Required for SEO."
|
||||
meta_description: "Meta description used within the head tag of the page. Required for SEO."
|
||||
domain_name: "ex: locomotiveapp.org"
|
||||
theme_asset:
|
||||
|
@ -53,10 +53,12 @@ fr:
|
||||
templatized: "Utilise la page comme un template pour un modèle défini."
|
||||
listed: "Controle si la page doit être visible depuis les menus automatiquement générés."
|
||||
content_type_id: "Le type du contenu pour lequel cette page est un template."
|
||||
meta_keywords: "Redéfinit les mots-clés du site. Utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule."
|
||||
meta_description: "Redéfinit la description du site. Utilisée à l'intérieur de la balise HEAD."
|
||||
snippet:
|
||||
slug: "Utilisé pour insérer le snippet dans une page."
|
||||
site:
|
||||
meta_keywords: "Mots-clés utilisés à l'intérieur de la balise HEAD. Ils sont séparés par un espace. Requis pour un meilleur référencement."
|
||||
meta_keywords: "Mots-clés utilisés à l'intérieur de la balise HEAD. Ils sont séparés par une virgule. Requis pour un meilleur référencement."
|
||||
meta_description: "Description utilisée à l'intérieur de la balise HEAD. Requis pour un meilleur référencement."
|
||||
domain_name: "ex: locomotiveapp.org"
|
||||
theme_asset:
|
||||
|
@ -2,6 +2,7 @@ module Locomotive
|
||||
module Liquid
|
||||
module Drops
|
||||
class Content < Base
|
||||
delegate :meta_keywords, :meta_description, :to => "@source"
|
||||
|
||||
def before_method(meth)
|
||||
return '' if @source.nil?
|
||||
|
@ -2,6 +2,7 @@ module Locomotive
|
||||
module Liquid
|
||||
module Drops
|
||||
class Page < Base
|
||||
delegate :meta_keywords, :meta_description, :to => "@source"
|
||||
|
||||
def title
|
||||
@source.templatized? ? @context['content_instance'].highlighted_field_value : @source.title
|
||||
|
@ -5,8 +5,8 @@ module Locomotive
|
||||
|
||||
def render(context)
|
||||
%{
|
||||
<meta name="description" content="#{sanitized_string(context.registers[:site].meta_description)}" />
|
||||
<meta name="keywords" content="#{sanitized_string(context.registers[:site].meta_keywords)}" />
|
||||
<meta name="description" content="#{sanitized_string(meta_description(context))}" />
|
||||
<meta name="keywords" content="#{sanitized_string(meta_keywords(context))}" />
|
||||
}
|
||||
end
|
||||
|
||||
@ -15,6 +15,19 @@ module Locomotive
|
||||
string.strip.gsub(/"/, '')
|
||||
end
|
||||
|
||||
def meta_description(context)
|
||||
object = metadata_object(context)
|
||||
object.try(:meta_description).blank? ? context.registers[:site].meta_description : object.meta_description
|
||||
end
|
||||
|
||||
def meta_keywords(context)
|
||||
object = metadata_object(context)
|
||||
object.try(:meta_keywords).blank? ? context.registers[:site].meta_keywords : object.meta_keywords
|
||||
end
|
||||
|
||||
def metadata_object(context)
|
||||
context['content_instance'] || context['page']
|
||||
end
|
||||
end
|
||||
|
||||
::Liquid::Template.register_tag('seo_metadata', SEOMetadata)
|
||||
|
@ -17,10 +17,10 @@ Gem::Specification.new do |s|
|
||||
s.required_rubygems_version = ">= 1.3.6"
|
||||
s.rubyforge_project = "nowarning"
|
||||
|
||||
s.add_dependency "rails", ">= 3.0.6"
|
||||
s.add_dependency "rails", ">= 3.0.7"
|
||||
s.add_dependency "warden"
|
||||
s.add_dependency "devise", "1.1.3"
|
||||
s.add_dependency "mongoid", "2.0.0.rc.7"
|
||||
s.add_dependency "mongoid", "2.0.1"
|
||||
s.add_dependency "bson_ext", "~> 1.3.0"
|
||||
s.add_dependency "locomotive_mongoid_acts_as_tree", "0.1.5.5"
|
||||
s.add_dependency "will_paginate"
|
||||
@ -37,7 +37,7 @@ Gem::Specification.new do |s|
|
||||
s.add_dependency "rmagick", "2.12.2"
|
||||
s.add_dependency "locomotive_carrierwave", "0.5.0.1.beta3"
|
||||
|
||||
s.add_dependency "custom_fields", "1.0.0.beta.10"
|
||||
s.add_dependency "custom_fields", "1.0.0.beta.12"
|
||||
s.add_dependency "fog", "0.3.7"
|
||||
s.add_dependency "mimetype-fu"
|
||||
s.add_dependency "actionmailer-with-request"
|
||||
|
@ -80,7 +80,7 @@ $(document).ready(function() {
|
||||
$('#submenu > ul > li.' + css).addClass('on');
|
||||
|
||||
// form
|
||||
$('.formtastic li input, .formtastic li textarea, .formtastic li code').focus(function() {
|
||||
$('.formtastic li input, .formtastic li textarea, .formtastic li code, .formtastic li select').focus(function() {
|
||||
$('.formtastic li.error:not(.code) p.inline-errors').fadeOut(200);
|
||||
if ($(this).parent().hasClass('error')) {
|
||||
$(this).nextAll('p.inline-errors').show();
|
||||
|
@ -50,7 +50,7 @@ $(document).ready(function() {
|
||||
// edit
|
||||
domField.find('a.edit').click(function(e) {
|
||||
var link = $(this);
|
||||
var attributes = ['_alias', 'hint', 'text_formatting'];
|
||||
var attributes = ['_alias', 'hint', 'text_formatting', 'target'];
|
||||
|
||||
$.fancybox({
|
||||
titleShow: false,
|
||||
@ -76,6 +76,8 @@ $(document).ready(function() {
|
||||
domBoxAttrVal(name, val);
|
||||
});
|
||||
if (domFieldVal(domField, 'kind').toLowerCase() == 'text') domBoxAttr('text_formatting').parents('li').show();
|
||||
if (domFieldVal(domField, 'kind').toLowerCase() == 'has_one' ||
|
||||
domFieldVal(domField, 'kind').toLowerCase() == 'has_many') domBoxAttr('target').parents('li').show();
|
||||
}
|
||||
});
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
@ -200,161 +202,5 @@ $(document).ready(function() {
|
||||
}
|
||||
}
|
||||
|
||||
setup(); // <- let's the show begin
|
||||
});
|
||||
|
||||
// $(document).ready(function() {
|
||||
//
|
||||
// $('fieldset.fields').parents('form').submit(function() {
|
||||
// $('fieldset.fields li.template input, fieldset.fields li.template select').attr('disabled', 'disabled');
|
||||
// });
|
||||
//
|
||||
// var defaultValue = $('fieldset.fields li.template input[type=text]').val();
|
||||
// var selectOnChange = function(select) {
|
||||
// select.hide();
|
||||
// select.prev()
|
||||
// .show()
|
||||
// .html(select[0].options[select[0].options.selectedIndex].text);
|
||||
// }
|
||||
//
|
||||
// var refreshPosition = function() {
|
||||
// jQuery.each($('fieldset.fields li.added input.position'), function(index) {
|
||||
// $(this).val(index);
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// /* __ fields ___ */
|
||||
// $('fieldset.fields li.added select').each(function() {
|
||||
// var select = $(this)
|
||||
// .hover(function() {
|
||||
// clearTimeout(select.attr('timer'));
|
||||
// }, function() {
|
||||
// select.attr('timer', setTimeout(function() {
|
||||
// select.hide();
|
||||
// select.prev().show();
|
||||
// }, 1000));
|
||||
// })
|
||||
// .change(function() { selectOnChange(select); });
|
||||
//
|
||||
// select.prev().click(function() {
|
||||
// $(this).hide();
|
||||
// select.show();
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// $('fieldset.fields li.template input[type=text]').focus(function() {
|
||||
// if ($(this).hasClass('void') && $(this).parents('li').hasClass('template'))
|
||||
// $(this).val('').removeClass('void');
|
||||
// });
|
||||
//
|
||||
// $('fieldset.fields li.template button').click(function() {
|
||||
// var lastRow = $(this).parents('li.template');
|
||||
//
|
||||
// var label = lastRow.find('input.label').val().trim();
|
||||
// if (label == '' || label == defaultValue) return false;
|
||||
//
|
||||
// var newRow = lastRow.clone(true).removeClass('template').addClass('added new').insertBefore(lastRow);
|
||||
//
|
||||
// var dateFragment = '[' + new Date().getTime() + ']';
|
||||
// newRow.find('input, select').each(function(index) {
|
||||
// $(this).attr('name', $(this).attr('name').replace('[-1]', dateFragment));
|
||||
// });
|
||||
//
|
||||
// var select = newRow.find('select')
|
||||
// .val(lastRow.find('select').val())
|
||||
// .change(function() { selectOnChange(select); })
|
||||
// .hover(function() {
|
||||
// clearTimeout(select.attr('timer'));
|
||||
// }, function() {
|
||||
// select.attr('timer', setTimeout(function() {
|
||||
// select.hide();
|
||||
// select.prev().show();
|
||||
// }, 1000));
|
||||
// });
|
||||
// select.prev()
|
||||
// .html(select[0].options[select[0].options.selectedIndex].text)
|
||||
// .click(function() {
|
||||
// $(this).hide();
|
||||
// select.show();
|
||||
// });
|
||||
//
|
||||
// // then "reset" the form
|
||||
// lastRow.find('input.label').val(defaultValue).addClass('void');
|
||||
//
|
||||
// // warn the sortable widget about the new row
|
||||
// $("fieldset.fields ol").sortable('refresh');
|
||||
//
|
||||
// refreshPosition();
|
||||
// });
|
||||
//
|
||||
// $('fieldset.fields li a.remove').click(function(e) {
|
||||
// if (confirm($(this).attr('data-confirm'))) {
|
||||
// var parent = $(this).parents('li');
|
||||
//
|
||||
// if (parent.hasClass('new'))
|
||||
// parent.remove();
|
||||
// else {
|
||||
// var field = parent.find('input.position')
|
||||
// field.attr('name', field.attr('name').replace('[position]', '[_destroy]'));
|
||||
//
|
||||
// parent.hide().removeClass('added')
|
||||
// }
|
||||
//
|
||||
// refreshPosition();
|
||||
// }
|
||||
//
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// });
|
||||
//
|
||||
// // sortable list
|
||||
// $("fieldset.fields ol").sortable({
|
||||
// handle: 'span.handle',
|
||||
// items: 'li:not(.template)',
|
||||
// axis: 'y',
|
||||
// update: refreshPosition
|
||||
// });
|
||||
//
|
||||
// // edit in depth custom field
|
||||
// $('fieldset.fields li.item span.actions a.edit').click(function() {
|
||||
// var link = $(this);
|
||||
// $.fancybox({
|
||||
// titleShow: false,
|
||||
// content: $(link.attr('href')).parent().html(),
|
||||
// onComplete: function() {
|
||||
// $('#fancybox-wrap form').submit(function(e) {
|
||||
// $.fancybox.close();
|
||||
// e.preventDefault();
|
||||
// e.stopPropagation();
|
||||
// });
|
||||
//
|
||||
// var parent = link.parent();
|
||||
//
|
||||
// if (parent.prevAll('select').val() == 'Text') {
|
||||
// var formatting = parent.prevAll('.text-formatting').val();
|
||||
// $('#fancybox-wrap #custom_fields_field_text_formatting').val(formatting);
|
||||
// $('#fancybox-wrap #custom_fields_field_text_formatting_input').show();
|
||||
// } else {
|
||||
// $('#fancybox-wrap #custom_fields_field_text_formatting_input').hide();
|
||||
// }
|
||||
//
|
||||
// var alias = parent.prevAll('.alias').val().trim();
|
||||
// if (alias == '') alias = makeSlug(link.parent().prevAll('.label').val());
|
||||
// $('#fancybox-wrap #custom_fields_field__alias').val(alias);
|
||||
//
|
||||
// var hint = parent.prevAll('.hint').val();
|
||||
// $('#fancybox-wrap #custom_fields_field_hint').val(hint);
|
||||
// },
|
||||
// onCleanup: function() {
|
||||
// var parent = link.parent();
|
||||
//
|
||||
// var alias = $('#fancybox-wrap #custom_fields_field__alias').val().trim();
|
||||
// if (alias != '') parent.prevAll('.alias').val(alias);
|
||||
// var hint = $('#fancybox-wrap #custom_fields_field_hint').val().trim();
|
||||
// if (hint != '') parent.prevAll('.hint').val(hint);
|
||||
// var formatting = $('#fancybox-wrap #custom_fields_field_text_formatting').val();
|
||||
// parent.prevAll('.text-formatting').val(formatting);
|
||||
// }
|
||||
// })
|
||||
// });
|
||||
// });
|
||||
setup(); // <- let the show begin
|
||||
});
|
161
public/javascripts/admin/custom_fields/has_many.js
Normal file
161
public/javascripts/admin/custom_fields/has_many.js
Normal file
@ -0,0 +1,161 @@
|
||||
$(document).ready(function() {
|
||||
// add/remove/sort items in a has_many relationship
|
||||
$('.has-many-selector').hasManySelector();
|
||||
});
|
||||
|
||||
(function($){
|
||||
$.fn.hasManySelector = function(options) {
|
||||
|
||||
var populateSelect = function(context) {
|
||||
context.select.find('option').remove();
|
||||
|
||||
for (var i = 0; i < context.data.collection.length; i++) {
|
||||
var obj = context.data.collection[i];
|
||||
if ($.inArray(obj[1], context.data.taken_ids) == -1)
|
||||
context.select.append(new Option(obj[0], obj[1], true, true));
|
||||
}
|
||||
|
||||
if (context.select.find('option').size() == 0)
|
||||
context.list.find('li.template').hide();
|
||||
else
|
||||
context.list.find('li.template').show();
|
||||
}
|
||||
|
||||
var addId = function(context, id) {
|
||||
context.data.taken_ids.push(id);
|
||||
|
||||
populateSelect(context);
|
||||
|
||||
if (context.data.taken_ids.length > 0) {
|
||||
context.empty.hide();
|
||||
context.list.next('input[type=hidden]').remove();
|
||||
}
|
||||
|
||||
if (context.data.taken_ids.length == context.data.collection.length)
|
||||
context.sep.hide();
|
||||
}
|
||||
|
||||
var removeId = function(context, id) {
|
||||
context.data.taken_ids = jQuery.grep(context.data.taken_ids, function(value) {
|
||||
return value != id;
|
||||
});
|
||||
|
||||
populateSelect(context);
|
||||
|
||||
if (context.data.taken_ids.length == 0) {
|
||||
context.empty.show();
|
||||
context.list.after('<input type="hidden" name="' + context.baseInputName + '" value="" />');
|
||||
}
|
||||
|
||||
context.sep.show();
|
||||
}
|
||||
|
||||
var registerElementEvents = function(context, data, domElement) {
|
||||
// remove
|
||||
domElement.find('a.remove').click(function(e) {
|
||||
domElement.remove();
|
||||
|
||||
removeId(context, data.id);
|
||||
|
||||
context.list.sortable('refresh');
|
||||
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
var registerElementTemplateEvents = function(context, domElement) {
|
||||
// bind the "Add field" button
|
||||
domElement.find('button').click(function(e) {
|
||||
var newElement = {
|
||||
id: context.select.val(),
|
||||
label: context.select.find('option:selected').text()
|
||||
};
|
||||
|
||||
addId(context, newElement.id);
|
||||
|
||||
addElement(context, newElement, { refreshPosition: true });
|
||||
|
||||
context.list.sortable('refresh');
|
||||
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
/* ___ Add an element into the list ___ */
|
||||
var addElement = function(context, data, options) {
|
||||
options = $.extend({
|
||||
'is_template': false,
|
||||
'refreshPosition': false
|
||||
}, options);
|
||||
|
||||
data = $.extend({
|
||||
behaviour_flag: function() { return options.is_template ? 'template' : 'added' },
|
||||
base_name: function() { return options.is_template ? '' : context.baseInputName },
|
||||
if_template: function() { return options.is_template }
|
||||
}, data);
|
||||
|
||||
var html = Mustache.to_html(context.template, data);
|
||||
|
||||
var domElement = null;
|
||||
|
||||
if (options.is_template) {
|
||||
domElement = context.list.append('<li class="sep"> </li>').append(html).find('.template');
|
||||
|
||||
context.sep = context.list.find('.sep');
|
||||
|
||||
registerElementTemplateEvents(context, domElement);
|
||||
}
|
||||
else {
|
||||
domElement = context.list.find('> .sep').before(html).prev('li');
|
||||
|
||||
registerElementEvents(context, data, domElement);
|
||||
|
||||
context.error.hide();
|
||||
|
||||
context.list.sortable('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
return this.each(function() {
|
||||
var wrapper = $(this);
|
||||
|
||||
var context = {
|
||||
list: wrapper.find('ul'),
|
||||
empty: wrapper.find('p:first'),
|
||||
template: wrapper.find('script[name=template]').html(),
|
||||
baseInputName: wrapper.find('script[name=template]').attr('data-base-input-name'),
|
||||
data: eval(wrapper.find('script[name=data]').html()),
|
||||
error: wrapper.parent().find('p.inline-errors')
|
||||
};
|
||||
|
||||
// sortable list
|
||||
context.list.sortable({
|
||||
handle: 'span.handle',
|
||||
items: 'li:not(.template)',
|
||||
axis: 'y'
|
||||
});
|
||||
|
||||
// add the template element used to insert the new ones
|
||||
addElement(context, null, { is_template: true });
|
||||
|
||||
context.select = wrapper.find('select[name=label]');
|
||||
populateSelect(context);
|
||||
|
||||
for (var i = 0; i < context.data.taken_ids.length; i++) {
|
||||
var data = { id: context.data.taken_ids[i], label: null };
|
||||
|
||||
for (var j = 0; j < context.data.collection.length; j++) {
|
||||
var current = context.data.collection[j];
|
||||
if (data.id == current[1])
|
||||
data.label = current[0];
|
||||
}
|
||||
|
||||
addElement(context, data);
|
||||
}
|
||||
|
||||
if (context.error.size() > 0)
|
||||
context.error.show();
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
||||
|
@ -1,3 +1,7 @@
|
||||
/* ___ AUTOMATICALLY GENERATED: see admin/button.scss for the source file */
|
||||
/* ___ rounded ___ */
|
||||
/* ___ box shadow ___ */
|
||||
/* ___ others ___ */
|
||||
.button {
|
||||
display: inline-block;
|
||||
background: transparent url(/images/admin/buttons/dark-gray-left.png) no-repeat 0 0;
|
||||
@ -7,49 +11,51 @@
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
height: 31px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button span {
|
||||
display: inline-block;
|
||||
background: transparent url(/images/admin/buttons/dark-gray-right.png) no-repeat right top;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
padding: 3px 9px 9px 4px;
|
||||
line-height: 21px;
|
||||
text-shadow: 1px 1px 1px #000;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button.light {
|
||||
background-image: url(/images/admin/buttons/light-gray-left.png);
|
||||
color: #787a89;
|
||||
}
|
||||
|
||||
.button.light span {
|
||||
background-image: url(/images/admin/buttons/light-gray-right.png);
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
.button.small {
|
||||
background: #ebedf4;
|
||||
outline: none;
|
||||
-moz-border-radius : 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
height: 20px;
|
||||
font-size: 0.7em;
|
||||
padding: 0px 12px 0px 12px;
|
||||
color: #8B8D9A !important;
|
||||
text-decoration: none;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
.button.small.add {
|
||||
}
|
||||
|
||||
.button.remove {
|
||||
color: #ff092c !important;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.button.remove:hover { text-decoration: underline; }
|
||||
outline: none; }
|
||||
.button span {
|
||||
display: inline-block;
|
||||
background: transparent url(/images/admin/buttons/dark-gray-right.png) no-repeat right top;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
padding: 3px 9px 9px 4px;
|
||||
line-height: 21px;
|
||||
text-shadow: 1px 1px 1px #000;
|
||||
outline: none; }
|
||||
.button.light {
|
||||
background-image: url(/images/admin/buttons/light-gray-left.png);
|
||||
color: #787a89; }
|
||||
.button.light span {
|
||||
background-image: url(/images/admin/buttons/light-gray-right.png);
|
||||
text-shadow: 1px 1px 1px #fff; }
|
||||
.button.small {
|
||||
background: #ebedf4;
|
||||
outline: none;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
height: 20px;
|
||||
font-size: 0.7em;
|
||||
padding: 0px 12px 0px 12px;
|
||||
color: #8B8D9A !important;
|
||||
text-decoration: none;
|
||||
text-shadow: 1px 1px 1px #fff; }
|
||||
.button.mini.add {
|
||||
background: transparent;
|
||||
height: 20px;
|
||||
background: #e1e4ed;
|
||||
background: -moz-linear-gradient(0% 100% 90deg, #d7dbe7, #ebedf4);
|
||||
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ebedf4), to(#d7dbe7));
|
||||
border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px;
|
||||
box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
|
||||
-moz-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
|
||||
-webkit-box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4); }
|
||||
.button.mini.add span {
|
||||
background: none;
|
||||
line-height: 10px;
|
||||
padding: 0px 5px 0 0; }
|
||||
.button.remove {
|
||||
color: #ff092c !important;
|
||||
font-size: 1.1em; }
|
||||
.button.remove:hover {
|
||||
text-decoration: underline; }
|
||||
|
@ -434,6 +434,85 @@ form.formtastic fieldset ol li.file p.remove a {
|
||||
|
||||
form.formtastic fieldset ol li.file p.remove a:hover { text-decoration: underline; }
|
||||
|
||||
form.formtastic fieldset ol li.has-many p {
|
||||
font-style: italic;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul {
|
||||
width: 736px;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.item {
|
||||
background: transparent url(/images/admin/form/item-popup.png) no-repeat 0 0;
|
||||
width: 413px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.item strong {
|
||||
font-size: 0.9em;
|
||||
font-weight: bold;
|
||||
color: #17171d;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.item span.handle {
|
||||
cursor: move;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.added span.actions a.remove {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.added span.actions button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.sep {
|
||||
border-top: 1px solid #ccc;
|
||||
height: 2px;
|
||||
margin: 5px 0 7px;
|
||||
width: 433px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template {}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template select {
|
||||
display: inline;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template span.handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template span.actions {
|
||||
width: auto;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template span.actions a.remove {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template span.actions button {
|
||||
display: inline;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
form.formtastic fieldset ol li.has-many ul li.template span.actions button span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ___ my account ___ */
|
||||
|
||||
form.formtastic fieldset.language li.full span {
|
||||
|
126
public/stylesheets/sass/admin/buttons.scss
Normal file
126
public/stylesheets/sass/admin/buttons.scss
Normal file
@ -0,0 +1,126 @@
|
||||
/* ___ AUTOMATICALLY GENERATED: see admin/button.scss for the source file */
|
||||
|
||||
@import "helpers";
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
background: transparent url(/images/admin/buttons/dark-gray-left.png) no-repeat 0 0;
|
||||
padding: 0px 0px 0px 2px;
|
||||
font-size: 0.9em;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
height: 31px;
|
||||
outline: none;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
background: transparent url(/images/admin/buttons/dark-gray-right.png) no-repeat right top;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
padding: 3px 9px 9px 4px;
|
||||
line-height: 21px;
|
||||
text-shadow: 1px 1px 1px #000;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-image: url(/images/admin/buttons/light-gray-left.png);
|
||||
color: #787a89;
|
||||
|
||||
span {
|
||||
background-image: url(/images/admin/buttons/light-gray-right.png);
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
background: #ebedf4;
|
||||
outline: none;
|
||||
-moz-border-radius : 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
height: 20px;
|
||||
font-size: 0.7em;
|
||||
padding: 0px 12px 0px 12px;
|
||||
color: #8B8D9A !important;
|
||||
text-decoration: none;
|
||||
text-shadow: 1px 1px 1px #fff;
|
||||
}
|
||||
|
||||
&.mini.add {
|
||||
background: transparent;
|
||||
height: 20px;
|
||||
@include linear-background-gradient(#ebedf4, #d7dbe7);
|
||||
@include full-rounded(4px);
|
||||
@include box-shadow(1px, 1px, 1px, rgba(0, 0, 0, 0.4));
|
||||
|
||||
span {
|
||||
background: none;
|
||||
line-height: 10px;
|
||||
padding: 0px 5px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.remove {
|
||||
color: #ff092c !important;
|
||||
font-size: 1.1em;
|
||||
|
||||
&:hover { text-decoration: underline; }
|
||||
}
|
||||
}
|
||||
|
||||
// .button {
|
||||
// display: inline-block;
|
||||
// background: transparent url(/images/admin/buttons/dark-gray-left.png) no-repeat 0 0;
|
||||
// padding: 0px 0px 0px 2px;
|
||||
// font-size: 0.9em;
|
||||
// color: white;
|
||||
// cursor: pointer;
|
||||
// border: none;
|
||||
// height: 31px;
|
||||
// outline: none;
|
||||
// }
|
||||
//
|
||||
// .button span {
|
||||
// display: inline-block;
|
||||
// background: transparent url(/images/admin/buttons/dark-gray-right.png) no-repeat right top;
|
||||
// position: relative;
|
||||
// top: -1px;
|
||||
// padding: 3px 9px 9px 4px;
|
||||
// line-height: 21px;
|
||||
// text-shadow: 1px 1px 1px #000;
|
||||
// outline: none;
|
||||
// }
|
||||
//
|
||||
// .button.light {
|
||||
// background-image: url(/images/admin/buttons/light-gray-left.png);
|
||||
// color: #787a89;
|
||||
// }
|
||||
//
|
||||
// .button.light span {
|
||||
// background-image: url(/images/admin/buttons/light-gray-right.png);
|
||||
// text-shadow: 1px 1px 1px #fff;
|
||||
// }
|
||||
//
|
||||
// .button.small {
|
||||
// background: #ebedf4;
|
||||
// outline: none;
|
||||
// -moz-border-radius : 10px;
|
||||
// -webkit-border-radius: 10px;
|
||||
// height: 20px;
|
||||
// font-size: 0.7em;
|
||||
// padding: 0px 12px 0px 12px;
|
||||
// color: #8B8D9A !important;
|
||||
// text-decoration: none;
|
||||
// text-shadow: 1px 1px 1px #fff;
|
||||
// }
|
||||
//
|
||||
// .button.small.add {
|
||||
// }
|
||||
//
|
||||
// .button.remove {
|
||||
// color: #ff092c !important;
|
||||
// font-size: 1.1em;
|
||||
// }
|
||||
//
|
||||
// .button.remove:hover { text-decoration: underline; }
|
27
spec/lib/locomotive/liquid/drops/content_spec.rb
Normal file
27
spec/lib/locomotive/liquid/drops/content_spec.rb
Normal file
@ -0,0 +1,27 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Drops::Content do
|
||||
|
||||
before(:each) do
|
||||
@site = Factory.build(:site)
|
||||
content_type = Factory.build(:content_type)
|
||||
content_type.content_custom_fields.build :label => 'anything', :kind => 'String'
|
||||
@content = content_type.contents.build(:meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.")
|
||||
end
|
||||
|
||||
describe 'meta_keywords' do
|
||||
subject { render_template('{{ content.meta_keywords }}') }
|
||||
it { should == @content.meta_keywords }
|
||||
end
|
||||
|
||||
describe 'meta_description' do
|
||||
subject { render_template('{{ content.meta_description }}') }
|
||||
it { should == @content.meta_description }
|
||||
end
|
||||
|
||||
def render_template(template = '', assigns = {})
|
||||
assigns = { 'content' => @content }.merge(assigns)
|
||||
Liquid::Template.parse(template).render(::Liquid::Context.new({}, assigns, { :site => @site }))
|
||||
end
|
||||
|
||||
end
|
@ -3,7 +3,8 @@ require 'spec_helper'
|
||||
describe Locomotive::Liquid::Drops::Page do
|
||||
|
||||
before(:each) do
|
||||
@home = Factory.build(:page)
|
||||
site = Factory.build(:site)
|
||||
@home = Factory.build(:page, :site => site, :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.")
|
||||
end
|
||||
|
||||
context '#rendering tree' do
|
||||
@ -56,6 +57,16 @@ describe Locomotive::Liquid::Drops::Page do
|
||||
|
||||
end
|
||||
|
||||
describe 'meta_keywords' do
|
||||
subject { render_template('{{ home.meta_keywords }}') }
|
||||
it { should == @home.meta_keywords }
|
||||
end
|
||||
|
||||
describe 'meta_description' do
|
||||
subject { render_template('{{ home.meta_description }}') }
|
||||
it { should == @home.meta_description }
|
||||
end
|
||||
|
||||
def render_template(template = '', assigns = {})
|
||||
assigns = {
|
||||
'home' => @home
|
||||
|
@ -1,19 +1,17 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Locomotive::Liquid::Tags::SEOMetadata do
|
||||
|
||||
before :each do
|
||||
@site = Factory.build(:site, :meta_description => 'A short site description', :meta_keywords => 'test only cat dog')
|
||||
let(:site) do
|
||||
Factory.build(:site, :meta_description => 'A short site description', :meta_keywords => 'test only cat dog')
|
||||
end
|
||||
|
||||
context '#rendering' do
|
||||
|
||||
describe 'rendering' do
|
||||
it 'renders a a meta description tag' do
|
||||
render_seo_metadata.should include '<meta name="description" content="A short site description" />'
|
||||
end
|
||||
|
||||
it 'strips and removes quote characters from the description' do
|
||||
@site.meta_description = ' String with " " quotes '
|
||||
site.meta_description = ' String with " " quotes '
|
||||
render_seo_metadata.should include '<meta name="description" content="String with quotes" />'
|
||||
end
|
||||
|
||||
@ -22,16 +20,53 @@ describe Locomotive::Liquid::Tags::SEOMetadata do
|
||||
end
|
||||
|
||||
it 'strips and removes quote characters from the keywords' do
|
||||
@site.meta_keywords = ' one " two " three '
|
||||
site.meta_keywords = ' one " two " three '
|
||||
render_seo_metadata.should include '<meta name="keywords" content="one two three" />'
|
||||
end
|
||||
|
||||
context "when page" do
|
||||
context "has metadata" do
|
||||
let(:page) { site.pages.build(:meta_keywords => 'hulk,gamma', :meta_description => "Bruce Banner") }
|
||||
subject { render_seo_metadata('page' => page) }
|
||||
it { should include(%Q[<meta name="keywords" content="#{page.meta_keywords}" />]) }
|
||||
it { should include(%Q[<meta name="description" content="#{page.meta_description}" />]) }
|
||||
end
|
||||
|
||||
context "does not have metadata" do
|
||||
let(:page) { site.pages.build }
|
||||
subject { render_seo_metadata('page' => page) }
|
||||
it { should include(%Q[<meta name="keywords" content="#{site.meta_keywords}" />]) }
|
||||
it { should include(%Q[<meta name="description" content="#{site.meta_description}" />]) }
|
||||
end
|
||||
end
|
||||
|
||||
context "when content instance" do
|
||||
let(:content_type) do
|
||||
Factory.build(:content_type, :site => site).tap do |ct|
|
||||
ct.content_custom_fields.build :label => 'anything', :kind => 'String'
|
||||
end
|
||||
end
|
||||
|
||||
context "has metadata" do
|
||||
let(:content) { content_type.contents.build(:meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") }
|
||||
subject { render_seo_metadata('content_instance' => content) }
|
||||
it { should include(%Q[<meta name="keywords" content="#{content.meta_keywords}" />]) }
|
||||
it { should include(%Q[<meta name="description" content="#{content.meta_description}" />]) }
|
||||
end
|
||||
|
||||
context "does not have metadata" do
|
||||
let(:content) { content_type.contents.build }
|
||||
subject { render_seo_metadata('content_instance' => content) }
|
||||
it { should include(%Q[<meta name="keywords" content="#{site.meta_keywords}" />]) }
|
||||
it { should include(%Q[<meta name="description" content="#{site.meta_description}" />]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_seo_metadata
|
||||
registers = { :site => @site }
|
||||
liquid_context = ::Liquid::Context.new({}, {}, registers)
|
||||
def render_seo_metadata(assigns={})
|
||||
registers = { :site => site }
|
||||
liquid_context = ::Liquid::Context.new({}, assigns, registers)
|
||||
output = Liquid::Template.parse("{% seo_metadata %}").render(liquid_context)
|
||||
end
|
||||
|
||||
end
|
@ -93,6 +93,13 @@ describe ContentInstance do
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe '#site' do
|
||||
it 'delegates to the content type' do
|
||||
@content_type.expects(:site)
|
||||
build_content.site
|
||||
end
|
||||
end
|
||||
|
||||
def build_content(options = {})
|
||||
@content_type.contents.build({ :title => 'Locomotive', :description => 'Lorem ipsum....' }.merge(options))
|
||||
@ -101,5 +108,4 @@ describe ContentInstance do
|
||||
def fake_bson_id(id)
|
||||
BSON::ObjectId(id.to_s.rjust(24, '0'))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -229,8 +229,6 @@ describe Page do
|
||||
@page.redirect_url = "invalid url with spaces"
|
||||
@page.should_not be_valid
|
||||
@page.errors[:redirect_url].should == ["is invalid"]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user