content_instance becomes now content_entry with its shortcut content_type.entries + change references to the old custom_fields API

This commit is contained in:
did 2011-12-23 00:45:32 +01:00
parent 9130544516
commit e9ef4d48c3
99 changed files with 681 additions and 818 deletions

View File

@ -7,16 +7,6 @@ GIT
fssm (>= 0.2.7)
sass (~> 3.1)
GIT
remote: git://github.com/locomotivecms/custom_fields.git
revision: 1a8f26a379193c5a60f926eacadc0a9eee7ab5de
branch: experimental
specs:
custom_fields (2.0.0.rc1)
activesupport (~> 3.1.3)
carrierwave-mongoid (~> 0.1.3)
mongoid (~> 2.3.4)
GIT
remote: git://github.com/plataformatec/devise.git
revision: ede004169c6af7416f8c4e3fc29a653bee133f60
@ -38,6 +28,14 @@ GIT
specs:
locomotive_mongoid_acts_as_tree (0.1.5.7)
PATH
remote: ../gems/custom_fields
specs:
custom_fields (2.0.0.rc1)
activesupport (~> 3.1.3)
carrierwave-mongoid (~> 0.1.3)
mongoid (~> 2.3.4)
GEM
remote: http://rubygems.org/
specs:

View File

@ -50,7 +50,7 @@ task :spec_nix do
lib/locomotive/heroku_spec.rb
lib/locomotive/import_spec.rb
lib/locomotive/export_spec.rb
models/content_instance_spec.rb
models/content_entry_spec.rb
models/editable_element_spec.rb
models/account_spec.rb
models/content_type_spec.rb

View File

@ -1,11 +0,0 @@
class Locomotive.Models.Content extends Backbone.Model
paramRoot: 'content'
urlRoot: "#{Locomotive.mount_on}/content_type/:slug/contents"
class Locomotive.Models.ContentsCollection extends Backbone.Collection
model: Locomotive.Models.Content
url: "#{Locomotive.mount_on}/content_type/:slug/contents"

View File

@ -0,0 +1,11 @@
class Locomotive.Models.ContentEntry extends Backbone.Model
paramRoot: 'content_entry'
urlRoot: "#{Locomotive.mount_on}/content_type/:slug/entries"
class Locomotive.Models.ContentEntriesCollection extends Backbone.Collection
model: Locomotive.Models.Content
url: "#{Locomotive.mount_on}/content_type/:slug/entries"

View File

@ -9,12 +9,12 @@ class Locomotive.Models.ContentType extends Backbone.Model
_normalize: ->
@set
contents_custom_fields: new Locomotive.Models.CustomFieldsCollection(@get('contents_custom_fields'))
entries_custom_fields: new Locomotive.Models.CustomFieldsCollection(@get('entries_custom_fields'))
toJSON: ->
_.tap super, (hash) =>
delete hash.contents_custom_fields
hash.contents_custom_fields_attributes = @get('contents_custom_fields').toJSONForSave() if @get('contents_custom_fields')
delete hash.entries_custom_fields
hash.entries_custom_fields_attributes = @get('entries_custom_fields').toJSONForSave() if @get('entries_custom_fields')
class Locomotive.Models.ContentTypesCollection extends Backbone.Collection

View File

@ -0,0 +1,21 @@
#= require ../shared/form_view
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.FormView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.ContentEntry(@options.content_entry)
Backbone.ModelBinding.bind @
render: ->
super()
return @

View File

@ -0,0 +1,6 @@
Locomotive.Views.ContentEntries ||= {}
class Locomotive.Views.ContentEntries.EditView extends Locomotive.Views.ContentEntries.FormView
save: (event) ->
@save_in_ajax event

View File

@ -1,6 +1,6 @@
Locomotive.Views.Contents ||= {}
class Locomotive.Views.Contents.NewView extends Locomotive.Views.Contents.FormView
class Locomotive.Views.ContentEntries.NewView extends Locomotive.Views.ContentEntries.FormView
save: (event) ->
@save_in_ajax event,

View File

@ -62,7 +62,7 @@ class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.For
target.show()
show_error: (attribute, message, html) ->
if attribute == 'contents_custom_fields'
if attribute == 'entries_custom_fields'
return if _.isEmpty(message)
for _message, index in message
@custom_fields_view._entry_views[index].show_error(_message[0])

View File

@ -44,7 +44,7 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
if labelInput.val() != ''
custom_field = new Locomotive.Models.CustomField label: labelInput.val(), type: typeInput.val()
@model.get('contents_custom_fields').add(custom_field)
@model.get('entries_custom_fields').add(custom_field)
@_insert_entry(custom_field)
@ -60,17 +60,17 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
remove_entry: (custom_field, view) ->
@_entry_views = _.reject @_entry_views, (_view) -> _view == view
@model.get('contents_custom_fields').remove(custom_field)
@model.get('entries_custom_fields').remove(custom_field)
@refresh_position_entries()
@$('> .empty').show() if @model.get('contents_custom_fields').length == 0
@$('> .empty').show() if @model.get('entries_custom_fields').length == 0
render_entries: ->
if @model.get('contents_custom_fields').length == 0
if @model.get('entries_custom_fields').length == 0
@$('> .empty').show()
else
@model.get('contents_custom_fields').each (custom_field) =>
@model.get('entries_custom_fields').each (custom_field) =>
@_insert_entry(custom_field)
_insert_entry: (custom_field) ->

View File

@ -1,21 +0,0 @@
#= require ../shared/form_view
Locomotive.Views.Contents ||= {}
class Locomotive.Views.Contents.FormView extends Locomotive.Views.Shared.FormView
el: '#content'
events:
'submit': 'save'
initialize: ->
@model = new Locomotive.Models.Content(@options.content)
Backbone.ModelBinding.bind @
render: ->
super()
return @

View File

@ -1,6 +0,0 @@
Locomotive.Views.Contents ||= {}
class Locomotive.Views.Contents.EditView extends Locomotive.Views.Contents.FormView
save: (event) ->
@save_in_ajax event

View File

@ -1,6 +1,8 @@
module Locomotive
class ApiContentsController < ActionController::Base
# FIXME: NEED REFACTORING
include Locomotive::Routing::SiteDispatcher
before_filter :require_site
@ -12,17 +14,17 @@ module Locomotive
before_filter :sanitize_content_params, :only => :create
def create
@content = @content_type.contents.build(params[:content])
@entry = @content_type.entries.build(params[:entry])
respond_to do |format|
if @content.save
format.json { render :json => { :content => @content } }
if @entry.save
format.json { render :json => { :entry => @entry } }
format.html do
flash[@content_type.slug.singularize] = @content.aliased_attributes
flash[@content_type.slug.singularize] = @entry.aliased_attributes
redirect_to params[:success_callback]
end
else
format.json { render :json => { :content => @content, :errors => @content.errors } }
format.json { render :json => { :entry => @content, :errors => @content.errors } }
format.html do
flash[@content_type.slug.singularize] = @content.aliased_attributes
flash['errors'] = @content.errors_to_hash

View File

@ -12,29 +12,29 @@ module Locomotive
before_filter :authorize_content
def index
@contents = @content_type.contents
respond_with @contents
@content_entries = @content_type.entries
respond_with @content_entries
end
def new
@content = @content_type.contents.build
@content_entry = @content_type.entries.build
respond_with @content
end
def create
@content = @content_type.contents.create(params[:content])
respond_with @content, :location => edit_content_url(@content_type.slug, @content._id)
@content_entry = @content_type.entries.create(params[:content_entry])
respond_with @content, :location => edit_content_entry_url(@content_type.slug, @content_entry._id)
end
def edit
@content = @content_type.contents.find(params[:id])
@content_entry = @content_type.entries.find(params[:id])
respond_with @content
end
def update
@content = @content_type.contents.find(params[:id])
@content.update_attributes(params[:content])
respond_with @content, :location => edit_content_url(@content_type.slug, @content._id)
@content_entry = @content_type.entries.find(params[:id])
@content_entry.update_attributes(params[:content_entry])
respond_with @content, :location => edit_content_entry_url(@content_type.slug, @content_entry._id)
end
def sort
@ -46,8 +46,8 @@ module Locomotive
end
def destroy
@content = @content_type.contents.find(params[:id])
@content.destroy
@content_entry = @content_type.entries.find(params[:id])
@content_entry.destroy
respond_with @content, :location => pages_url
end
@ -58,7 +58,7 @@ module Locomotive
end
def authorize_content
authorize! params[:action].to_sym, ContentInstance
authorize! params[:action].to_sym, ContentEntry
end
end

View File

@ -14,7 +14,6 @@ module Locomotive
def create
@content_type = current_site.content_types.create(params[:content_type])
logger.debug @content_type.contents_custom_fields.inspect
respond_with @content_type, :location => edit_content_type_url(@content_type._id)
end

View File

@ -1,33 +0,0 @@
module Locomotive
class CustomFieldsController < BaseController
layout false
before_filter :set_parent_and_fields
skip_load_and_authorize_resource
def edit
@field = @fields.find(params[:id])
render :action => "edit_#{@field.kind.downcase}"
end
def update
@field = @fields.find(params[:id])
if @field.update_attributes(params[:custom_field])
render :json => @field.to_json
else
render :json => { :error => t('flash.locomotive.custom_fields.update.alert') }
end
end
protected
def set_parent_and_fields
@parent = current_site.content_types.where(:slug => params[:slug]).first
@fields = @parent.contents_custom_fields
end
end
end

View File

@ -7,7 +7,7 @@ module Locomotive::ContentTypesHelper
item_on = (content_type.slug == @content_type.slug) rescue nil
label = truncate(content_type.name, :length => 15)
url = contents_url(content_type.slug)
url = content_entries_url(content_type.slug)
css = @content_type && content_type.slug == @content_type.slug ? 'on' : ''
html = submenu_entry(label, url, :i18n => false, :css => css) do

View File

@ -2,12 +2,12 @@ module Locomotive::CustomFieldsHelper
def options_for_custom_field_type
%w(string text select boolean date file).map do |type|
[t("custom_fields.kind.#{type}"), type]
[t("custom_fields.types.#{type}"), type]
end
end
def options_for_highlighted_field(content_type)
content_type.ordered_contents_custom_fields.find_all do |field|
content_type.ordered_entries_custom_fields.find_all do |field|
%w(string date select).include?(field.type)
end.map do |field|
[field.label, field._id]
@ -15,7 +15,7 @@ module Locomotive::CustomFieldsHelper
end
def options_for_group_by_field(content_type)
content_type.ordered_contents_custom_fields.find_all do |field|
content_type.ordered_entries_custom_fields.find_all do |field|
%w(select).include?(field.type)
end.map do |field|
[field.label, field._id]
@ -49,8 +49,8 @@ module Locomotive::CustomFieldsHelper
# klass_name = my_content_type.content_klass.to_s
#
# [].tap do |options|
# ContentType.where(:'contents_custom_fields.kind' => 'has_one', :'contents_custom_fields.target' => klass_name).each do |content_type|
# content_type.contents_custom_fields.find_all { |f| f.has_one? && f.target == klass_name }.each do |field|
# ContentType.where(:'entries_custom_fields.kind' => 'has_one', :'entries_custom_fields.target' => klass_name).each do |content_type|
# content_type.entries_custom_fields.find_all { |f| f.has_one? && f.target == klass_name }.each do |field|
# options << {
# :klass => content_type.content_klass.to_s,
# :label => field.label,

View File

@ -3,10 +3,10 @@ module Locomotive
default :from => Locomotive.config.mailer_sender
def new_content_instance(account, content)
@account, @content = account, content
def new_content_entry(account, entry)
@account, @entry = account, entry
subject = t('locomotive.notifications.new_content_instance.subject', :type => content.content_type.name, :locale => account.locale)
subject = t('locomotive.notifications.new_content_entry.subject', :type => entry.content_type.name, :locale => account.locale)
mail :subject => subject, :to => account.email
end

View File

@ -32,7 +32,7 @@ module Locomotive
can :touch, [Page, ThemeAsset]
can :sort, Page
can :manage, [ContentInstance, ContentAsset]
can :manage, [ContentEntry, ContentAsset]
can :touch, Site do |site|
site == @site
@ -42,7 +42,7 @@ module Locomotive
def setup_designer_permissions!
can :manage, Page
can :manage, ContentInstance
can :manage, ContentEntry
can :manage, ContentType

View File

@ -1,5 +1,5 @@
module Locomotive
class ContentInstance
class ContentEntry
include Locomotive::Mongoid::Document
@ -72,7 +72,7 @@ module Locomotive
end
def to_presenter
Locomotive::ContentPresenter.new(self)
Locomotive::ContentEntryPresenter.new(self)
end
def as_json(options = {})

View File

@ -20,7 +20,7 @@ module Locomotive
## associations ##
belongs_to :site, :class_name => 'Locomotive::Site'
has_many :contents, :class_name => 'Locomotive::ContentInstance', :dependent => :destroy
has_many :entries, :class_name => 'Locomotive::ContentEntry', :dependent => :destroy
## named scopes ##
scope :ordered, :order_by => :updated_at.desc
@ -37,10 +37,10 @@ module Locomotive
## validations ##
validates_presence_of :site, :name, :slug
validates_uniqueness_of :slug, :scope => :site_id
validates_size_of :contents_custom_fields, :minimum => 1, :message => :array_too_short
validates_size_of :entries_custom_fields, :minimum => 1, :message => :array_too_short
## behaviours ##
custom_fields_for :contents
custom_fields_for :entries
## methods ##
@ -49,11 +49,11 @@ module Locomotive
# end
def highlighted_field
self.contents_custom_fields.find(self.highlighted_field_id)
self.entries_custom_fields.find(self.highlighted_field_id)
end
def group_by_field
self.contents_custom_fields.find(self.group_by_field_id)
self.entries_custom_fields.find(self.group_by_field_id)
end
def order_manually?
@ -102,7 +102,7 @@ module Locomotive
#
# conditions.each do |key, value|
# # convert alias (key) to name
# field = self.contents_custom_fields.detect { |f| f._alias == key }
# field = self.entries_custom_fields.detect { |f| f._alias == key }
#
# case field.kind.to_sym
# when :category
@ -130,18 +130,18 @@ module Locomotive
# end
#
# def highlighted_field
# self.contents_custom_fields.detect { |f| f._name == self.highlighted_field_name }
# self.entries_custom_fields.detect { |f| f._name == self.highlighted_field_name }
# end
#
# def group_by_field
# @group_by_field ||= self.contents_custom_fields.detect { |f| f._name == self.group_by_field_name }
# @group_by_field ||= self.entries_custom_fields.detect { |f| f._name == self.group_by_field_name }
# end
protected
def set_default_values
self.order_by ||= 'created_at'
self.highlighted_field_id ||= self.contents_custom_fields.first._id
self.highlighted_field_id ||= self.entries_custom_fields.first._id
end
def normalize_slug
@ -150,13 +150,13 @@ module Locomotive
end
def bubble_fields_errors_up
return if self.errors[:contents_custom_fields].empty?
return if self.errors[:entries_custom_fields].empty?
self.errors.set(:contents_custom_fields, [])
self.errors.set(:entries_custom_fields, [])
self.contents_custom_fields.each do |field|
self.entries_custom_fields.each do |field|
next if field.valid?
self.errors.add(:contents_custom_fields, field.errors.to_a)
self.errors.add(:entries_custom_fields, field.errors.to_a)
end
end

View File

@ -1,5 +1,5 @@
module Locomotive
class ContentPresenter < BasePresenter
class ContentEntryPresenter < BasePresenter
# delegate :name, :description, :slug, :order_by, :order_direction, :highlighted_field_name, :group_by_field_name, :api_accounts, :to => :source

View File

@ -3,12 +3,12 @@ module Locomotive
delegate :name, :description, :slug, :order_by, :order_direction, :highlighted_field_name, :group_by_field_name, :api_accounts, :to => :source
def contents_custom_fields
self.source.ordered_contents_custom_fields.collect(&:as_json)
def entries_custom_fields
self.source.ordered_entries_custom_fields.collect(&:as_json)
end
def included_methods
super + %w(name description slug order_by order_direction highlighted_field_name group_by_field_name api_accounts contents_custom_fields)
super + %w(name description slug order_by order_direction highlighted_field_name group_by_field_name api_accounts entries_custom_fields)
end
end

View File

@ -15,7 +15,7 @@
= f.inputs :name => :custom_fields, :class => "inputs foldable" do
= f.input :contents_custom_fields, :as => :'Locomotive::Empty', :label => false, :wrapper_html => { :id => 'custom_fields_input' }
= f.input :entries_custom_fields, :as => :'Locomotive::Empty', :label => false, :wrapper_html => { :id => 'custom_fields_input' }
- if @content_type.persisted?

View File

@ -7,8 +7,8 @@
= render 'locomotive/shared/actions/contents'
- content_for :buttons do
= local_action_button :show_items, contents_url(@content_type.slug_was), :class => 'show'
= local_action_button :new_item, new_content_url(@content_type.slug_was), :class => 'new'
= local_action_button :show_items, content_entries_url(@content_type.slug_was), :class => 'show'
= local_action_button :new_item, new_content_entry_url(@content_type.slug_was), :class => 'new'
%p!= t('.help')
@ -16,4 +16,4 @@
= render 'form', :f => f
= render 'locomotive/shared/form_actions', :back_url => contents_url(@content_type.slug_was), :button_label => :update
= render 'locomotive/shared/form_actions', :back_url => content_entries_url(@content_type.slug_was), :button_label => :update

View File

@ -1,21 +0,0 @@
- title t('.title', :type => @content_type.name.capitalize)
- content_for :submenu do
= render 'locomotive/shared/menu/contents'
- content_for :actions do
= render 'locomotive/shared/actions/contents'
- content_for :buttons do
- if can?(:manage, Locomotive::ContentType)
= local_action_button t('locomotive.contents.index.edit'), edit_content_type_url(@content_type), :class => 'edit'
= local_action_button t('locomotive.contents.index.new'), new_content_url(@content_type.slug), :class => 'new'
%p= @content_type.description
= semantic_form_for @content, :as => :content, :url => content_url(@content_type.slug, @content), :html => { :multipart => true } do |form|
= render 'form', :f => form
= render 'locomotive/shared/form_actions', :back_url => contents_url(@content_type.slug), :button_label => :update

View File

@ -1,5 +1,5 @@
- if contents.empty?
%p.no-items!= t('.no_items', :url => new_content_url(@content_type.slug))
%p.no-items!= t('.no_items', :url => new_content_entry_url(@content_type.slug))
- else
%ul{ :id => 'contents-list', :class => "list #{'sortable' if @content_type.order_by == '_position_in_list'}", :'data-url' => sort_admin_contents_path(@content_type.slug, :json) }
- contents.each do |content|

View File

@ -0,0 +1,21 @@
- title t('.title', :type => @content_type.name.capitalize)
- content_for :submenu do
= render 'locomotive/shared/menu/contents'
- content_for :actions do
= render 'locomotive/shared/actions/contents'
- content_for :buttons do
- if can?(:manage, Locomotive::ContentType)
= local_action_button t('locomotive.content_entries.index.edit'), edit_content_type_url(@content_type), :class => 'edit'
= local_action_button t('locomotive.content_entries.index.new'), new_content_entry_url(@content_type.slug), :class => 'new'
%p= @content_type.description
= semantic_form_for @content, :as => :content, :url => content_entry_url(@content_type.slug, @content), :html => { :multipart => true } do |form|
= render 'form', :f => form
= render 'locomotive/shared/form_actions', :back_url => content_entries_url(@content_type.slug), :button_label => :update

View File

@ -13,7 +13,7 @@
- if can?(:manage, Locomotive::ContentType)
= local_action_button :edit, edit_content_type_url(@content_type), :class => 'edit'
= local_action_button :new, new_content_url(@content_type.slug), :class => 'new'
= local_action_button :new, new_content_entry_url(@content_type.slug), :class => 'new'
- if @content_type.description.present?
%p= @content_type.description

View File

@ -8,12 +8,12 @@
- if can?(:manage, Locomotive::ContentType)
- content_for :buttons do
= local_action_button t('locomotive.contents.index.edit'), edit_content_type_url(@content_type), :class => 'edit'
= local_action_button t('locomotive.content_entries.index.edit'), edit_content_type_url(@content_type), :class => 'edit'
%p= @content_type.description
= semantic_form_for @content, :as => :content, :url => contents_url(@content_type.slug), :html => { :multipart => true } do |form|
= semantic_form_for @content, :as => :content, :url => content_entries_url(@content_type.slug), :html => { :multipart => true } do |form|
= render 'form', :f => form
= render 'locomotive/shared/form_actions', :back_url => contents_url(@content_type.slug), :button_label => :create
= render 'locomotive/shared/form_actions', :back_url => content_entries_url(@content_type.slug), :button_label => :create

View File

@ -0,0 +1,21 @@
%p= t('.title', :name => @account.name, :date => I18n.l(Time.now), :locale => @account.locale)
%hr
%p
%b= t('.type', :type => @content_entry.content_type.name, :locale => @account.locale)
%br
%i= @content_entry.content_type.description
%hr
%ul
- @content_entry.custom_fields.each do |field|
%li
%strong= field.label
&nbsp;-&nbsp;
%i
- if field.file?
= link_to File.basename(@content_entry.send(field.name).url), @content_entry.send(field.name).url
- else
= @content_entry.send(field.name)

View File

@ -1,21 +0,0 @@
%p= t('.title', :name => @account.name, :date => I18n.l(Time.now), :locale => @account.locale)
%hr
%p
%b= t('.type', :type => @content.content_type.name, :locale => @account.locale)
%br
%i= @content.content_type.description
%hr
%ul
- @content.custom_fields.each do |field|
%li
%strong= field.label
&nbsp;-&nbsp;
%i
- if field.file?
= link_to File.basename(@content.send(field._name).url), @content.send(field._name).url
- else
= @content.send(field._alias)

View File

@ -14,13 +14,13 @@
- each_content_type_menu_item do |content_type|
.wrapper
.header
%p= link_to t('locomotive.contents.index.new'), new_content_url(content_type.slug)
%p= link_to t('locomotive.content_entries.index.new'), new_content_entry_url(content_type.slug)
- if can? :manage, content_type
%p.edit= link_to t('locomotive.contents.index.edit'), edit_content_type_url(content_type)
%p.edit= link_to t('locomotive.content_entries.index.edit'), edit_content_type_url(content_type)
.inner
%h2!= t('locomotive.contents.index.lastest_items')
%h2!= t('locomotive.content_entries.index.lastest_items')
/ %ul
/ - content_type.latest_updated_contents.each do |content|
/ %li

View File

@ -10,7 +10,7 @@ xml.urlset "xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9" do
if not page.index_or_not_found?
if page.templatized?
page.content_type.contents.visible.each do |c|
page.content_type.entries.visible.each do |c|
xml.url do
xml.loc page_url(page, { :content => c, :host => true })
xml.lastmod c.updated_at.to_date.to_s('%Y-%m-%d')

View File

@ -44,7 +44,7 @@ de:
link: "&rarr; Zurück zur Anwendung"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] neu"
title: "Hi %{firstname}, nur damit du Bescheid weißt! Am %{date} wurde folgende neue Instanz erstellt."
type: "Model: %{type}"
@ -55,15 +55,7 @@ de:
text_formatting:
none: Keine
html: HTML
edit_field:
title: Feld bearbeiten
edit_category:
title: Optionen
help: Organisiere alle Optionen für die Auswahlbox.
collection_label: Liste der Optionen
types:
category:
edit_categories: Optionen
file:
delete_file: Datei löschen
index:
@ -239,7 +231,7 @@ de:
asc: Aufsteigend
desc: Absteigend
contents:
content_entries:
index:
title: '"%{type}" anzeigen'
edit: Baustein bearbeiten
@ -247,18 +239,14 @@ de:
download: Elemente herunterladen
new: neues Element
category_noname: "Kein Name"
lastest_items: "Neueste Elemente"
lastest_entries: "Neueste Elemente"
updated_at: "Aktualisiert am"
list:
no_items: "Momentan gibt es keine Elemente. Klicke einfach <a href='%{url}'>hier</a>, um das erste Element zu erstellen."
no_entries: "Momentan gibt es keine Elemente. Klicke einfach <a href='%{url}'>hier</a>, um das erste Element zu erstellen."
new:
title:
default: '%{type} &mdash; neues Element'
breadcrumb: '%{root} &raquo; %{type} &mdash; Element bearbeiten'
title: '%{type} &mdash; neues Element'
edit:
title:
default: '%{type} &mdash; editing item'
breadcrumb: '%{root} &raquo; %{type} &mdash; Element bearbeiten'
title: '%{type} &mdash; editing item'
form:
has_many:
new_item: Neues Element

View File

@ -47,7 +47,7 @@ en:
link: "&rarr; Back to the application"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] new"
title: "Hi %{name}, just to let you know that a new instance has been created on %{date}"
type: "Model: %{type}"
@ -61,15 +61,7 @@ en:
text_formatting:
none: None
html: HTML
edit_field:
title: Edit field
edit_category:
title: Edit options
help: Manage the list of options for your select box.
collection_label: List of options
types:
category:
edit_categories: Edit options
file:
delete_file: Delete file
has_many:
@ -243,7 +235,7 @@ en:
asc: Ascending
desc: Descending
contents:
content_entries:
index:
title: 'Listing "%{type}"'
edit: edit model

View File

@ -46,7 +46,7 @@ es:
send: Enviar
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] nuevo"
title: "Hola %{name}, queremos hacerte saber que una nueva instancia se creó el día %{date}"
type: "Modelo: %{type}"
@ -57,15 +57,7 @@ es:
text_formatting:
none: Ninguno
html: HTML
edit_field:
title: Editar campo
edit_category:
title: Editar opciones
help: Gestionar la lista de opciones que aparecerán en la lista desplegable.
collection_label: Lista de opciones
types:
category:
edit_categories: Editar opciones
file:
delete_file: Borrar fichero
has_many:
@ -236,7 +228,7 @@ es:
asc: Ascendente
desc: Descendente
contents:
content_entries:
index:
title: 'Mostrando "%{type}"'
edit: editar modelo
@ -244,18 +236,14 @@ es:
download: descargar elementos
new: nuevo elemento
category_noname: "Sin nombre"
lastest_items: "Últimos elementos"
lastest_entries: "Últimos elementos"
updated_at: "Última actualización"
list:
no_items: "No hay ningún elemento. Haga click <a href=\"%{url}\">aquí</a> para crear el primero."
no_entries: "No hay ningún elemento. Haga click <a href=\"%{url}\">aquí</a> para crear el primero."
new:
title:
default: '%{type} &mdash; nuevo elemento'
breadcrumb: '%{root} &raquo; %{type} &mdash; nuevo elemento'
title: '%{type} &mdash; nuevo elemento'
edit:
title:
default: '%{type} &mdash; editando elemento'
breadcrumb: '%{root} &raquo; %{type} &mdash; editando elemento'
title: '%{type} &mdash; editando elemento'
form:
has_many:
new_item: Nuevo elemento

View File

@ -46,7 +46,7 @@ fr:
send: Envoyer
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] nouveau"
title: "Bonjour %{name}, nous voulions vous faire savoir qu'une nouvelle instance a été créée le %{date}"
type: "Modèle: %{type}"
@ -60,15 +60,7 @@ fr:
text_formatting:
none: Aucun
html: HTML
edit_field:
title: Editer champ
edit_category:
title: Editer options
help: Gèrer la liste des options de votre liste déroulante
collection_label: Liste des options
types:
category:
edit_categories: Editer options
file:
delete_file: Supprimer fichier
has_many:
@ -240,7 +232,7 @@ fr:
asc: Ascendant
desc: Descendant
contents:
content_entries:
index:
title: 'Liste des "%{type}"'
edit: éditer modèle
@ -248,18 +240,14 @@ fr:
download: télécharger éléments
new: nouvel élément
category_noname: "Pas de nom"
lastest_items: "Eléments récents"
lastest_entries: "Eléments récents"
updated_at: "Mis à jour le"
list:
no_items: "Il n'existe pas d'éléments. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>"
no_entries: "Il n'existe pas d'éléments. Vous pouvez commencer par créer un <a href='%{url}'>ici</a>"
new:
title:
default: '%{type} &mdash; nouvel élément'
breadcrumb: '%{root} &raquo; %{type} &mdash; nouvel élément'
title: '%{type} &mdash; nouvel élément'
edit:
title:
default: '%{type} &mdash; édition élément'
breadcrumb: '%{root} &raquo; %{type} &mdash; édition élément'
title: '%{type} &mdash; édition élément'
form:
has_many:
new_item: Nouvel élément

View File

@ -46,7 +46,7 @@ it:
link: "&rarr; Ritorna all'applicazione"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] nuovo/a"
title: "Ciao %{name}, solo per farti sapere che una nuova istanza è stata creata il %{date}"
type: "Modello: %{type}"
@ -60,15 +60,7 @@ it:
text_formatting:
none: Nessuno
html: HTML
edit_field:
title: Modifica campo
edit_category:
title: Modifica opzioni
help: Amministra la lista opzioni del select box.
collection_label: Lista delle opzioni
types:
category:
edit_categories: Modifica opzioni
file:
delete_file: Elimina file
index:
@ -235,7 +227,7 @@ it:
asc: Ascendente
desc: Discendente
contents:
content_entries:
index:
title: 'Lista "%{type}"'
edit: modifica modello
@ -243,18 +235,14 @@ it:
download: scarica elementi
new: nuovo elemento
category_noname: "Senza nome"
lastest_items: "Ultimi elementi"
lastest_entries: "Ultimi elementi"
updated_at: "modificato il"
list:
no_items: "Per ora non ci sono elementi. Clicca <a href=\"%{url}\">qui</a> per creare il primo."
no_entries: "Per ora non ci sono elementi. Clicca <a href=\"%{url}\">qui</a> per creare il primo."
new:
title:
default: '%{type} &mdash; nuovo elemento'
breadcrumb: '%{root} &raquo; %{type} &mdash; nuovo elemento'
title: '%{type} &mdash; nuovo elemento'
edit:
title:
default: '%{type} &mdash; modifica elemento'
breadcrumb: '%{root} &raquo; %{type} &mdash; modifica elemento'
title: '%{type} &mdash; modifica elemento'
form:
has_many:
new_item: Nuovo elemento

View File

@ -43,7 +43,7 @@ nl:
link: "&rarr; Terug naar de applicatie"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] nieuw"
title: "Hallo %{name}, dit bericht is om te laten weten dat er een nieuwe instantie is gemaakt op %{date}"
type: "Model: %{type}"
@ -54,14 +54,7 @@ nl:
text_formatting:
none: Geen
html: HTML
edit_field:
title: Bewerk veld
edit_category:
title: Bewerk opties
help: Beheer de lijst met opties voor uw select box.
collection_label: Lijst met opties
custom_form:
edit_categories: Bewerk opties
delete_file: Verwijder bestand
index:
is_required: is verplicht
@ -219,7 +212,7 @@ nl:
asc: Oplopend
desc: Aflopend
contents:
content_entries:
index:
title: 'Toon "%{type}"'
edit: wijzig model
@ -227,18 +220,14 @@ nl:
download: download items
new: nieuw item
category_noname: "Geen naam"
lastest_items: "Laatste items"
lastest_entries: "Laatste items"
updated_at: "Gewijzigd op"
list:
no_items: "Er zijn momenteel geen items. Klik hier <a href=\"%{url}\">here</a> om de eerste te maken."
no_entries: "Er zijn momenteel geen items. Klik hier <a href=\"%{url}\">here</a> om de eerste te maken."
new:
title:
default: '%{type} &mdash; nieuw item'
breadcrumb: '%{root} &raquo; %{type} &mdash; nieuw item'
title: '%{type} &mdash; nieuw item'
edit:
title:
default: '%{type} &mdash; wijzig item'
breadcrumb: '%{root} &raquo; %{type} &mdash; wijzig item'
title: '%{type} &mdash; wijzig item'
form:
has_many:
new_item: Nieuw item

View File

@ -46,7 +46,7 @@
link: "&rarr; Tilbake til applikasjonen"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] ny"
title: "Hei %{name}, varsler om at en ny instanse ble opprettet %{date}"
type: "Modell: %{type}"
@ -60,15 +60,7 @@
text_formatting:
none: Ingen
html: HTML
edit_field:
title: Rediger felt
edit_category:
title: Rediger innstillinger
help: Rediger listen med innstillinger i select-boksen
collection_label: Liste med innstillinger
types:
category:
edit_categories: Rediger innstillinger
file:
delete_file: Slett fil
has_many:
@ -237,7 +229,7 @@
asc: Stigende
desc: Synkende
contents:
content_entries:
index:
title: 'Viser alle "%{type}"'
edit: rediger modell
@ -245,18 +237,14 @@
download: last ned elementer
new: nytt element
category_noname: "Navn mangler"
lastest_items: "Siste elementer"
lastest_entries: "Siste elementer"
updated_at: "Sist oppdatert"
list:
no_items: "Det har ikke blitt opprettet noen elementer her ennå. Klikk <a href=\"%{url}\">her</a> for å opprette det første."
no_entries: "Det har ikke blitt opprettet noen elementer her ennå. Klikk <a href=\"%{url}\">her</a> for å opprette det første."
new:
title:
default: '%{type} &mdash; nytt element'
breadcrumb: '%{root} &raquo; %{type} &mdash; nytt element'
title: '%{type} &mdash; nytt element'
edit:
title:
default: '%{type} &mdash; rediger element'
breadcrumb: '%{root} &raquo; %{type} &mdash; rediger element'
title: '%{type} &mdash; rediger element'
form:
has_many:
new_item: Nytt element

View File

@ -43,7 +43,7 @@ pt-BR:
link: "&rarr; Voltar a aplicação"
notifications:
new_content_instance:
new_content_entry:
subject: " Novo [%{type}] "
title: "Olá %{name}, apenas informando que uma nova instância foi criada em %{date}"
type: "Modelo: %{type}"
@ -54,15 +54,7 @@ pt-BR:
text_formatting:
none: Nenhum
html: HTML
edit_field:
title: Edita campo
edit_category:
title: Editar opções
help: Gerenciar a lista de opções da sua caixa de seleçõa.
collection_label: Lista de opções
types:
category:
edit_categories: Editar opções
file:
delete_file: Excluir arquivo
@ -215,7 +207,7 @@ pt-BR:
updated_at: 'Por "atualizado em" data'
position_in_list: Manual
contents:
content_entries:
index:
title: 'Listando "%{type}"'
edit: editar modelo
@ -223,18 +215,14 @@ pt-BR:
download: download dos itens
new: novo item
category_noname: "Sem nome"
lastest_items: "Últimos itens"
lastest_entries: "Últimos itens"
updated_at: "Atualizado em"
list:
no_items: "Não existem itens ainda. Clique <a href=\"%{url}\">aqui</a> para criar o primeiro."
no_entries: "Não existem itens ainda. Clique <a href=\"%{url}\">aqui</a> para criar o primeiro."
new:
title:
default: '%{type} &mdash; novo item'
breadcrumb: '%{root} &raquo; %{type} &mdash; novo item'
title: '%{type} &mdash; novo item'
edit:
title:
default: '%{type} &mdash; editando item'
breadcrumb: '%{root} &raquo; %{type} &mdash; editando item'
title: '%{type} &mdash; editando item'
form:
has_many:
new_item: Novo item

View File

@ -46,7 +46,7 @@ ru:
link: "&rarr; Назад в приложение"
notifications:
new_content_instance:
new_content_entry:
subject: "[%{type}] новый"
title: "Привет %{name}, просто сообщаем, что новый элемент был создан %{date}"
type: "Модель: %{type}"
@ -60,15 +60,7 @@ ru:
text_formatting:
none: None
html: HTML
edit_field:
title: Редактировать поле
edit_category:
title: Редактировать опции
help: Управляйте списком опций для поля выбора select.
collection_label: Списко опций
types:
category:
edit_categories: Редактировать опции
file:
delete_file: Удалить файл
has_many:
@ -236,7 +228,7 @@ ru:
asc: По возрастанию
desc: По убыванию
contents:
content_entries:
index:
title: 'Список "%{type}"'
edit: редактировать модель
@ -244,18 +236,14 @@ ru:
download: скачать элементы
new: новый элемент
category_noname: "Без имени"
lastest_items: "Элементы за последнее время"
lastest_entries: "Элементы за последнее время"
updated_at: "Обновлено"
list:
no_items: "На данный момент нет ни одного элемента. Нажмите <a href=\"%{url}\">здесь</a> для создания первого элемента."
no_entries: "На данный момент нет ни одного элемента. Нажмите <a href=\"%{url}\">здесь</a> для создания первого элемента."
new:
title:
default: '%{type} &mdash; новый элемент'
breadcrumb: '%{root} &raquo; %{type} &mdash; новый элемент'
title: '%{type} &mdash; новый элемент'
edit:
title:
default: '%{type} &mdash; редактирование элемента'
breadcrumb: '%{root} &raquo; %{type} &mdash; редактирование элемента'
title: '%{type} &mdash; редактирование элемента'
form:
has_many:
new_item: Новый элемент

View File

@ -95,7 +95,7 @@ es:
access_password: "Clave"
custom_fields:
field:
_alias: Alias
name: Alias
hint: Ayuda
required: Obligatorio
text_formatting: Formato

View File

@ -95,7 +95,7 @@ fr:
access_password: "Mot de passe"
custom_fields:
field:
_alias: Alias
name: Alias
hint: Aide
required: Requis ?
text_formatting: Formattage

View File

@ -100,7 +100,7 @@ it:
access_password: Password
custom_fields:
field:
_alias: Alias
name: Alias
hint: Aiuto
required: Obbligatorio
text_formatting: Formattazione

View File

@ -13,7 +13,7 @@ de:
destroy:
notice: "Seite wurde erfolgreich gelöscht."
contents:
content_entries:
create:
notice: "Inhalt wurde erfolgreich erstellt."
alert: "Inhalt wurde nicht erstellt."

View File

@ -13,17 +13,17 @@ en:
destroy:
notice: "Page was successfully deleted."
contents:
content_entries:
create:
notice: "Content was successfully created."
alert: "Content was not created."
notice: "Entry was successfully created."
alert: "Entry was not created."
update:
notice: "Content was successfully updated."
alert: "Content was not updated."
notice: "Entry was successfully updated."
alert: "Entry was not updated."
sort:
notice: "Contents were successfully sorted."
notice: "Entries were successfully sorted."
destroy:
notice: "Content was successfully deleted."
notice: "Entry was successfully deleted."
content_types:
create:

View File

@ -13,7 +13,7 @@ es:
destroy:
notice: "Página borrada con éxito."
contents:
content_entries:
create:
notice: "Contenido multimedia creado con éxito."
alert: "El contenido multimedia no se pudo crear."

View File

@ -13,7 +13,7 @@ fr:
destroy:
notice: "La page a été supprimée avec succès."
contents:
content_entries:
create:
notice: "L'élément a été crée avec succès."
alert: "L'élément a été crée avec succès."

View File

@ -13,7 +13,7 @@ it:
destroy:
notice: "La pagina è stata eliminata con successo."
contents:
content_entries:
create:
notice: "Il contenuto è stato creato con successo."
alert: "Il contenuto non è stato creato."

View File

@ -13,7 +13,7 @@ nl:
destroy:
notice: "Pagina is verwijderd."
contents:
content_entries:
create:
notice: "Inhoud is gemaakt."
alert: "Inhoud is niet gemaakt."

View File

@ -13,7 +13,7 @@
destroy:
notice: "Siden har blitt slettet."
contents:
content_entries:
create:
notice: "Innholdet har blitt opprettet."
alert: "Innholdet kunne ikke opprettes."

View File

@ -13,7 +13,7 @@ pt-BR:
destroy:
notice: "Páginas foram apagadas com sucesso."
contents:
content_entries:
create:
notice: "Conteúdo criado com sucesso."
alert: "Conteúdo não foi criado."

View File

@ -13,7 +13,7 @@ ru:
destroy:
notice: "Страницы успешно удалены."
contents:
content_entries:
create:
notice: "Контент успешно создан."
alert: "Контент не создан."

View File

@ -30,7 +30,7 @@ de:
source: Datei ersetzen
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: Datei
@ -69,7 +69,7 @@ de:
custom_fields:
field:
_alias: "Merkmal verfügbar in den liquid-Templates"
name: "Merkmal verfügbar in den liquid-Templates"
hint: "Hilfe-Text, der im Formular des Bausteins direkt unter dem jeweiligen Feld angezeigt wird"
import:
source: "Eine zip-Datei, die eine databse.yml, Assets und Templates enthält"

View File

@ -32,7 +32,7 @@ en:
source: Replace file
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: File
@ -44,7 +44,7 @@ en:
public_form_accounts: Notified Accounts
"custom_fields/field":
select_options: "Options"
content_instance:
content_entry:
_slug: Permalink
account:
edit:
@ -82,7 +82,7 @@ en:
source: "The current file is available here %{url}"
update:
source: "The current file is available here %{url}"
content_instance:
content_entry:
_slug: "Property used to generate the url of a page working as a template for this content type (ex: \"template_page/{{ your_object._permalink }})\"."
seo_title: "The value you fill in will replace the SEO title of the templatized page related to your model."
meta_keywords: "Overrides the site's meta keywords used within the head tag of the page. They are separated by a comma."

View File

@ -30,7 +30,7 @@ es:
source: Reemplazar fichero
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: Fichero
@ -72,7 +72,7 @@ es:
source: "El fichero está disponible aquí: %{url}"
custom_fields:
field:
_alias: "Propiedad disponible en plantillas Liquid"
name: "Propiedad disponible en plantillas Liquid"
hint: "Texto mostrado justo debajo del campo en el formulario de creación"
import:
source: "Un fichero zip conteniendo un fichero database.yml con plantillas y contenido multimedia."

View File

@ -34,7 +34,7 @@ fr:
source: Nouveau fichier
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: Fichier
@ -43,7 +43,7 @@ fr:
content_type:
item_template: Template d'affichage
api_accounts: Comptes à notifier
content_instance:
content_entry:
_slug: Permalink
account:
edit:
@ -81,9 +81,9 @@ fr:
source: "Le fichier actuel est accessible ici %{url}"
custom_fields:
field:
_alias: "Champ utilisable dans les templates liquid"
name: "Champ utilisable dans les templates liquid"
hint: "Texte affiché dans le formulaire de l'élément juste en dessous du champ."
content_instance:
content_entry:
_slug: "Propriété utilisée pour générer l'url d'une page faisant office de template pour ce modèle (ex: \"template_de_la_page/{{ votre_object._permalink }})\"."
seo_title: "La valeur que vous rentrez sera utilisée comme titre SEO pour la page faisant office de template pour ce modèle."
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."

View File

@ -32,7 +32,7 @@ it:
source: Sostituire file
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: File
@ -42,14 +42,14 @@ it:
content_type:
item_template: Template di elemento
api_accounts: Destinatari notifiche
content_instance:
_slug: Permalink
content_entry:
_slug: Permalink
account:
edit:
password: Nuova password
password_confirmation: Conferma nuova password
page:
seo_title: Title
seo_title: Title
hints:
page:
@ -81,9 +81,9 @@ it:
source: "Il corrente file è disponibile qui %{url}"
custom_fields:
field:
_alias: "Proprietà disponibile nei tamplate liquid"
name: "Proprietà disponibile nei tamplate liquid"
hint: "Testo visualizzato nel form del modello appena sotto il campo"
content_instance:
content_entry:
_slug: "Proprità utilizzata per generare l'url della pagina di template per questo contenuto (es: \"template_page/{{ your_object._permalink }})\"."
seo_title: "Il valore del tag title della pagina che visualizza questo contenuto."
meta_keywords: "Sovrascrive le meta keywords per questo contenuto. Separate da virgola."

View File

@ -30,7 +30,7 @@ nl:
source: Vervang bestand
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: Bestand
@ -72,7 +72,7 @@ nl:
source: "Het huidige bestand is hier beschikbaar %{url}"
custom_fields:
field:
_alias: "Eigenschap is beschikbaar in liquid templates"
name: "Eigenschap is beschikbaar in liquid templates"
hint: "Net beneden het veld staat de tekst in het model formulier"
import:
source: "Een .zip bestand met een database.yml met de bronbestanden en templates"

View File

@ -32,7 +32,7 @@
source: Erstatt fil
custom_fields:
field:
_alias: Alias
name: Alias
import:
new:
source: Fil
@ -42,7 +42,7 @@
content_type:
item_template: Elementmal
api_accounts: Varslede kontoer
content_instance:
content_entry:
_slug: Permalink
account:
edit:
@ -81,9 +81,9 @@
source: "Filen er tilgjengelig her: %{url}"
custom_fields:
field:
_alias: "Verdi tilgjengelig i liquid-maler"
name: "Verdi tilgjengelig i liquid-maler"
hint: "Tekst som vises i skjemaet rett under feltet"
content_instance:
content_entry:
_slug: "Verdien brukes til å generere en url for en side som fungerer som en mal for denne innholdstypen (f.eks: \"template_page/{{ your_object._permalink }})\"."
seo_title: "Verdien benyttes til å erstatte sidetittelen for malen knyttet til modellen. Leses av søkemotorer."
meta_keywords: "Overstyrer sidens meta-nøkkelord som benyttes i head-seksjonen på siden og blir lest av søkemotorer. Separeres med komma."

View File

@ -29,7 +29,7 @@ pt-BR:
source: Substituir arquivo
custom_fields:
field:
_alias: Apelido
name: Apelido
import:
new:
source: Arquivo
@ -59,7 +59,7 @@ pt-BR:
source: "Você pode substituir por um arquivo com a mesma extensão."
custom_fields:
field:
_alias: "Propriedades disponíveis em templates líquidos."
name: "Propriedades disponíveis em templates líquidos."
hint: "Texto mostrado no formulário de modelo está abaixo do campo."
import:
source: "Um arquivo .zip contendo um database.yml com assets and templates"

View File

@ -32,7 +32,7 @@ ru:
source: Заменить файл
custom_fields:
field:
_alias: Алиас
name: Алиас
import:
new:
source: Файл
@ -42,7 +42,7 @@ ru:
content_type:
item_template: Шаблон элемента
api_accounts: Уведомленные аккаунты
content_instance:
content_entry:
_slug: Постоянная ссылка
account:
edit:
@ -81,9 +81,9 @@ ru:
source: "Текущий файл доступен здесь %{url}"
custom_fields:
field:
_alias: "Свойство, доступное в шаблонах liquid"
name: "Свойство, доступное в шаблонах liquid"
hint: "Текст, отображенный в форме модели, находится ниже поля"
content_instance:
content_entry:
_slug: "Свойство, используемое для генерации ссылки (url) на страницу, работающей как шаблон для этого типа содержимого (ex: \"template_page/{{ your_object._permalink }})\"."
seo_title: "Значение, вводимое вами, будет заменять SEO заголовок шаблонизированной страницы, связанной с вашей моделью."
meta_keywords: "Переопределяет meta keywords сайта, используемые внутри тэга head страницы. Разделяются запятыми."

View File

@ -37,7 +37,7 @@ Locomotive::Engine.routes.draw do
resources :content_types
resources :contents, :path => 'content_types/:slug/contents' do
resources :content_entries, :path => 'content_types/:slug/entries' do
put :sort, :on => :collection
end

View File

@ -53,6 +53,7 @@ x edit my site
- manage contents
- list (highlighted field)
- crud
- public_form (previously api something)
- disallow to click twice on the submit form button (spinner ?)
- message to notify people if their browser is too old

View File

@ -6,7 +6,7 @@ Feature: Editing a content type
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| label | type | required |
| Name | string | true |
| Description | text | false |
And I have a designer and an author

View File

@ -6,7 +6,7 @@ Feature: Pages
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| label | type | required |
| Name | string | true |
| Description | text | false |
And I have a designer and an author

View File

@ -6,7 +6,7 @@ Feature: Manage Content Types
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| label | type | required |
| Name | string | true |
| Description | text | false |
And I am an authenticated user

View File

@ -6,11 +6,11 @@ Feature: Create and manage has many relationships
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required | target |
| label | type | required | target |
| Name | string | true | |
| Description | text | false | |
And I have a custom model named "Clients" with
| label | kind | required | target |
| label | type | required | target |
| Name | string | true | |
| Description | string | false | |
| Projects | has_many | false | Projects |

View File

@ -6,11 +6,11 @@ Feature: Set up a has many reverse relationship
Background:
Given I have the site: "test site" set up
And I have a custom model named "Clients" with
| label | kind | required |
| label | type | required |
| Name | string | true |
| Description | string | false |
And I have a custom model named "Projects" with
| label | kind | required | target |
| label | type | required | target |
| Name | string | true | |
| Description | text | false | |
| Client | has_one | false | Clients |

View File

@ -6,10 +6,10 @@ Feature: Manage Contents
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| label | type | required |
| Name | string | true |
| Description | text | false |
| Category | category | false |
| Category | select | false |
And I have "Design, Development" as "Category" values of the "Projects" model
And I am an authenticated user
And I have entries for "Projects" with

View File

@ -5,7 +5,7 @@ Feature: TableRow liquid tags
Background:
Given I have the site: "test site" set up
And I have a custom model named "Projects" with
| label | kind | required |
| label | type | required |
| Name | string | true |
And I have entries for "Projects" with
| name |

View File

@ -7,7 +7,7 @@ Given %r{^I have a custom model named "([^"]*)" with$} do |name, fields|
field['target'] = target_content_type.content_klass.to_s
end
content_type.contents_custom_fields.build field
content_type.entries_custom_fields.build field
end
content_type.valid?
content_type.save.should be_true
@ -19,9 +19,9 @@ Given /^I set up a reverse has_many relationship between "([^"]*)" and "([^"]*)"
content_type_1 = site.content_types.where(:name => name_1).first
content_type_2 = site.content_types.where(:name => name_2).first
content_type_1.contents_custom_fields.build({
content_type_1.entries_custom_fields.build({
:label => name_2,
:kind => 'has_many',
:type => 'has_many',
:target => content_type_2.content_klass.to_s,
:reverse_lookup => content_type_2.content_klass.custom_field_alias_to_name(name_1.downcase.singularize)
})
@ -31,30 +31,30 @@ end
Given %r{^I have "([^"]*)" as "([^"]*)" values of the "([^"]*)" model$} do |values, field, name|
content_type = Locomotive::ContentType.where(:name => name).first
field = content_type.contents_custom_fields.detect { |f| f.label == field }
field = content_type.entries_custom_fields.detect { |f| f.label == field }
field.should_not be_nil
if field.category?
if field.type == 'select'
values.split(',').collect(&:strip).each do |name|
field.category_items.build :name => name
field.select_options.build :name => name
end
content_type.save.should be_true
else
raise "#{field.kind} field is not supported"
raise "#{field.type} field is not supported"
end
end
Given %r{^I have entries for "([^"]*)" with$} do |name, entries|
content_type = Locomotive::ContentType.where(:name => name).first
entries.hashes.each do |entry|
content_type.contents.create(entry)
content_type.entries.create(entry)
end
content_type.save.should be_true
end
When %r{^I change the presentation of the "([^"]*)" model by grouping items by "([^"]*)"$} do |name, field|
content_type = Locomotive::ContentType.where(:name => name).first
field = content_type.contents_custom_fields.detect { |f| f.label == field }
field = content_type.entries_custom_fields.detect { |f| f.label == field }
content_type.group_by_field_name = field._name
content_type.save.should be_true
end

View File

@ -1,15 +1,15 @@
Given %r{^I have an? "([^"]*)" model which has many "([^"]*)"$} do |parent_model, child_model|
@parent_model = FactoryGirl.build(:content_type, :site => @site, :name => parent_model).tap do |ct|
ct.contents_custom_fields.build :label => 'Body', :kind => 'string', :required => false
ct.entries_custom_fields.build :label => 'Body', :type => 'string', :required => false
ct.save!
end
@child_model = FactoryGirl.build(:content_type, :site => @site, :name => child_model).tap do |ct|
ct.contents_custom_fields.build :label => 'Body', :kind => 'string', :required => false
ct.contents_custom_fields.build :label => parent_model.singularize, :kind => 'has_one', :required => false, :target => parent_model
ct.entries_custom_fields.build :label => 'Body', :type => 'string', :required => false
ct.entries_custom_fields.build :label => parent_model.singularize, :kind => 'has_one', :required => false, :target => parent_model
ct.save!
end
@parent_model.contents_custom_fields.build({
@parent_model.entries_custom_fields.build({
:label => child_model,
:kind => 'has_many',
:target => @child_model.content_klass.to_s,
@ -22,12 +22,12 @@ Then /^I should be able to view a paginaed list of a has many association$/ do
step %{I have an "Articles" model which has many "Comments"}
# Create contents
article = @parent_model.contents.create!(:slug => 'parent', :body => 'Parent')
@child_model.contents.create!(:slug => 'one', :body => 'One', :custom_field_2 => article.id.to_s)
@child_model.contents.create!(:slug => 'two', :body => 'Two', :custom_field_2 => article.id.to_s)
@child_model.contents.create!(:slug => 'three', :body => 'Three', :custom_field_2 => article.id.to_s)
article = @parent_model.entries.create!(:slug => 'parent', :body => 'Parent')
@child_model.entries.create!(:slug => 'one', :body => 'One', :custom_field_2 => article.id.to_s)
@child_model.entries.create!(:slug => 'two', :body => 'Two', :custom_field_2 => article.id.to_s)
@child_model.entries.create!(:slug => 'three', :body => 'Three', :custom_field_2 => article.id.to_s)
@child_model.contents.each do |comment|
@child_model.entries.each do |comment|
article.comments << comment
end

View File

@ -1,12 +1,12 @@
Then /^I should be able to display paginated models$/ do
# Create our article model and three articles
@article_model = FactoryGirl.build(:content_type, :site => @site, :name => 'Articles').tap do |ct|
ct.contents_custom_fields.build :label => 'Body', :kind => 'string', :required => false
ct.entries_custom_fields.build :label => 'Body', :type => 'string', :required => false
ct.save!
end
%w(First Second Third).each do |body|
@article_model.contents.create!(:body => body)
@article_model.entries.create!(:body => body)
end
# Create a page with template

View File

@ -1,6 +1,6 @@
# Custom options for CustomFields
CustomFields.options = {
:reserved_aliases => Mongoid.destructive_fields + %w(created_at updated_at)
:reserved_names => Mongoid.destructive_fields + %w(created_at updated_at)
}
# Set correct paths
@ -20,15 +20,6 @@ module CustomFields
end
end
# module Category
# class Item
#
# def to_liquid
# { 'id' => self._id.to_s, 'name' => self.name }
# end
#
# end
# end
end
end

View File

@ -107,12 +107,14 @@ module Locomotive
@site.content_types.each do |content_type|
attributes = self.extract_attributes(content_type, %w(name description slug order_by order_direction group_by_field_name api_enabled))
attributes['highlighted_field_name'] = content_type.highlighted_field._alias
attributes['highlighted_field_name'] = content_type.highlighted_field.name
# TODO: refactoring
# custom_fields
fields = []
content_type.contents_custom_fields.each do |field|
field_attributes = self.extract_attributes(field, %w(label kind hint required))
content_type.entries_custom_fields.each do |field|
field_attributes = self.extract_attributes(field, %w(label type hint required))
if field.target.present?
target_klass = field['target'].constantize
@ -124,7 +126,7 @@ module Locomotive
end
end
fields << { field._alias => field_attributes }
fields << { field.name => field_attributes }
end
attributes['fields'] = fields
@ -275,15 +277,17 @@ module Locomotive
def extract_contents(content_type)
data = []
# TODO (refactoring....)
highlighted_field_name = content_type.highlighted_field_name
content_type.contents.each do |content|
content_type.entries.each do |content|
hash = {}
content.custom_fields.each do |field|
next if field._name == highlighted_field_name
value = (case field.kind
value = (case field.type
when 'file'
uploader = content.send(field._name)
unless uploader.blank?
@ -296,16 +300,16 @@ module Locomotive
when 'text'
self.replace_asset_urls_in(content.send(field._name.to_sym) || '')
when 'has_one'
content.send(field.safe_alias.to_sym).highlighted_field_value rescue nil # no bound object
content.send(field.name.to_sym).highlighted_field_value rescue nil # no bound object
when 'has_many'
unless field.reverse_has_many?
content.send(field.safe_alias.to_sym).collect(&:highlighted_field_value)
content.send(field.name.to_sym).collect(&:highlighted_field_value)
end
else
content.send(field.safe_alias.to_sym)
content.send(field.name.to_sym)
end)
hash[field._alias] = value if value.present? || value == false # False values should be preserved in the export
hash[field.name] = value if value.present? || value == false # False values should be preserved in the export
end
data << { content.highlighted_field_value => hash }

View File

@ -11,8 +11,8 @@ module Locomotive
protected
def add_theme_assets
%w(images media fonts javascripts stylesheets).each do |kind|
Dir[File.join(theme_path, 'public', kind, '**/*')].each do |asset_path|
%w(images media fonts javascripts stylesheets).each do |type|
Dir[File.join(theme_path, 'public', type, '**/*')].each do |asset_path|
next if File.directory?(asset_path)

View File

@ -24,7 +24,7 @@ module Locomotive
self.add_or_update_fields(content_type, attributes['fields'])
if content_type.contents_custom_fields.any? { |f| ['has_many', 'has_one'].include?(f.kind) }
if content_type.entries_custom_fields.any? { |f| ['has_many', 'has_one'].include?(f.type) }
content_types_with_associations << content_type
end
@ -80,17 +80,17 @@ module Locomotive
reverse_lookup = data.delete('reverse')
attributes = { :_alias => name, :label => name.humanize, :kind => 'string', :position => position }.merge(data).symbolize_keys
attributes = { :name => name, :label => name.humanize, :type => 'string', :position => position }.merge(data).symbolize_keys
field = content_type.contents_custom_fields.detect { |f| f._alias == attributes[:_alias] }
field = content_type.entries_custom_fields.detect { |f| f.name == attributes[:name] }
field ||= content_type.contents_custom_fields.build(attributes)
field ||= content_type.entries_custom_fields.build(attributes)
field.send(:set_unique_name!) if field.new_record?
field.attributes = attributes
field[:kind] = field[:kind].downcase # old versions of the kind field are capitalized
field[:type] = field[:type].downcase # old versions of the kind field are capitalized
field[:tmp_reverse_lookup] = reverse_lookup # use the ability in mongoid to set free attributes on the fly
end
@ -98,8 +98,8 @@ module Locomotive
def replace_target(content_types)
content_types.each do |content_type|
content_type.contents_custom_fields.each do |field|
next unless ['has_many', 'has_one'].include?(field.kind)
content_type.entries_custom_fields.each do |field|
next unless ['has_many', 'has_one'].include?(field.type)
target_content_type = site.content_types.where(:slug => field.target).first
@ -125,6 +125,8 @@ module Locomotive
associations = []
# TODO (needs refactoring)
# build with default attributes
content = content_type.contents.where(content_type.highlighted_field_name.to_sym => value).first
@ -141,24 +143,24 @@ module Locomotive
end
attributes.each do |name, value|
field = content_type.contents_custom_fields.detect { |f| f._alias == name }
field = content_type.entries_custom_fields.detect { |f| f.name == name }
next if field.nil? # the attribute name is not related to a field (name misspelled ?)
kind = field.kind
type = field.type
if ['has_many', 'has_one'].include?(kind)
associations << OpenStruct.new(:name => name, :kind => kind, :value => value, :target => field.target)
if ['has_many', 'has_one'].include?(type)
associations << OpenStruct.new(:name => name, :type => type, :value => value, :target => field.target)
next
end
value = (case kind
value = (case type
when 'file' then self.open_sample_asset(value)
when 'boolean' then Boolean.set(value)
when 'date' then value.is_a?(Date) ? value : Date.parse(value)
when 'category'
if field.category_items.detect { |item| item.name == value }.nil?
field.category_items.build :name => value
when 'select'
if field.select_options.detect { |item| item.name == value }.nil?
field.select_options.build :name => value
end
value
else # string, text
@ -193,7 +195,7 @@ module Locomotive
next if target_content_type.nil?
value = (case association.kind
value = (case association.type
when 'has_one' then
target_content_type.contents.detect { |c| c.highlighted_field_value == association.value }
when 'has_many' then
@ -210,7 +212,7 @@ module Locomotive
end
def set_highlighted_field_name(content_type)
field = content_type.contents_custom_fields.detect { |f| f._alias == content_type.highlighted_field_name.to_s }
field = content_type.entries_custom_fields.detect { |f| f.name == content_type.highlighted_field_name.to_s }
content_type.highlighted_field_name = field._name if field
end
@ -222,7 +224,7 @@ module Locomotive
when 'manually', '_position_in_list' then '_position_in_list'
when 'default', 'created_at' then 'created_at'
else
content_type.contents_custom_fields.detect { |f| f._alias == content_type.order_by }._name rescue nil
content_type.entries_custom_fields.detect { |f| f.name == content_type.order_by }._name rescue nil
end)
self.log "order by (after) #{order_by}"
@ -233,7 +235,7 @@ module Locomotive
def set_group_by_value(content_type)
return if content_type.group_by_field_name.blank?
field = content_type.contents_custom_fields.detect { |f| f._alias == content_type.group_by_field_name }
field = content_type.entries_custom_fields.detect { |f| f.name == content_type.group_by_field_name }
content_type.group_by_field_name = field._name if field
end

View File

@ -3,6 +3,8 @@ module Locomotive
module Drops
class Contents < ::Liquid::Drop
# TODO: refactoring
def before_method(meth)
type = @context.registers[:site].content_types.where(:slug => meth.to_s).first
ProxyCollection.new(type)
@ -52,7 +54,7 @@ module Locomotive
end
def before_method(meth)
klass = @content_type.contents.klass # delegate to the proxy class
klass = @content_type.entries.klass # delegate to the proxy class
if (meth.to_s =~ /^group_by_.+$/) == 0
klass.send(meth, :ordered_contents)

View File

@ -6,17 +6,17 @@ module Locomotive
delegate :seo_title, :meta_keywords, :meta_description, :to => '_source'
def title
self._source.templatized? ? @context['content_instance'].highlighted_field_value : self._source.title
self._source.templatized? ? @context['content_entry'].highlighted_field_value : self._source.title
end
def slug
self._source.templatized? ? self._source.content_type.slug.singularize : self._source.slug
end
def parent
@parent ||= self._source.parent.to_liquid
end
def breadcrumbs
@breadcrumbs ||= liquify(*self._source.self_and_ancestors)
end
@ -32,11 +32,11 @@ module Locomotive
def depth
self._source.depth
end
def listed?
self._source.listed?
end
def published?
self._source.published?
end

View File

@ -42,7 +42,7 @@ module Locomotive
end
def metadata_object(context)
context['content_instance'] || context['page']
context['content_entry'] || context['page']
end
end

View File

@ -45,9 +45,9 @@ module Locomotive
page = nil
else
if page.templatized?
@content_instance = page.content_type.contents.where(:_slug => File.basename(path.first)).first
@content_entry = page.content_type.entries.where(:_slug => File.basename(path.first)).first
if @content_instance.nil? || (!@content_instance.visible? && current_locomotive_account.nil?) # content instance not found or not visible
if @content_entry.nil? || (!@content_entry.visible? && current_locomotive_account.nil?) # content instance not found or not visible
page = nil
end
end
@ -75,8 +75,8 @@ module Locomotive
assigns.merge!(flash.to_hash.stringify_keys) # data from api
if @page.templatized? # add instance from content type
assigns['content_instance'] = @content_instance
assigns[@page.content_type.slug.singularize] = @content_instance # just here to help to write readable liquid code
assigns['content_entry'] = @content_entry
assigns[@page.content_type.slug.singularize] = @content_entry # just here to help to write readable liquid code
end
registers = {

View File

@ -5,10 +5,10 @@ describe Locomotive::ApiContentsController do
before(:each) do
@site = FactoryGirl.create('existing site')
@site.content_types.first.tap do |content_type|
content_type.contents_custom_fields.build :label => 'Name', :kind => 'string', :required => true
content_type.contents_custom_fields.build :label => 'Description', :kind => 'text'
content_type.contents_custom_fields.build :label => 'File', :kind => 'file'
content_type.contents_custom_fields.build :label => 'Active', :kind => 'boolean'
content_type.entries_custom_fields.build :label => 'Name', :type => 'string', :required => true
content_type.entries_custom_fields.build :label => 'Description', :type => 'text'
content_type.entries_custom_fields.build :label => 'File', :type => 'file'
content_type.entries_custom_fields.build :label => 'Active', :type => 'boolean'
end.save
controller.stubs(:require_site).returns(true)
@ -37,38 +37,38 @@ describe Locomotive::ApiContentsController do
response.should redirect_to('http://www.locomotivecms.com/success')
@site.reload.content_types.first.contents.size.should == 1
@site.reload.content_types.first.entries.size.should == 1
end
it 'does not save a content if required parameters are missing' do
post 'create', default_post_params(:content => { :name => '' })
post 'create', default_post_params(:content_entry => { :name => '' })
response.should redirect_to('http://www.locomotivecms.com/failure')
@site.reload.content_types.first.contents.size.should == 0
@site.reload.content_types.first.entries.size.should == 0
end
describe 'XSS vulnerability' do
it 'sanitizes the params (simple example)' do
post 'create', default_post_params(:content => { :name => %(Hacking <script type="text/javascript">alert("You have been hacked")</script>) })
post 'create', default_post_params(:content_entry => { :name => %(Hacking <script type="text/javascript">alert("You have been hacked")</script>) })
content = @site.reload.content_types.first.contents.first
entry = @site.reload.content_types.first.entries.first
content.name.should == "Hacking alert(\"You have been hacked\")"
entry.name.should == "Hacking alert(\"You have been hacked\")"
end
it 'sanitizes the params (more complex example)' do
post 'create', default_post_params(:content => { :name => %(<img src=javascript:alert('Hello')><table background="javascript:alert('Hello')">Hacked) })
post 'create', default_post_params(:content_entry => { :name => %(<img src=javascript:alert('Hello')><table background="javascript:alert('Hello')">Hacked) })
content = @site.reload.content_types.first.contents.first
entry = @site.reload.content_types.first.entries.first
content.name.should == "Hacked"
entry.name.should == "Hacked"
end
it 'does not sanitize non string params' do
lambda {
post 'create', default_post_params(:content => {
post 'create', default_post_params(:content_entry => {
:active => true,
:file => ActionDispatch::Http::UploadedFile.new(:tempfile => FixturedAsset.open('5k.png'), :filename => '5k.png', :content_type => 'image/png')
})
@ -82,7 +82,7 @@ describe Locomotive::ApiContentsController do
def default_post_params(options = {})
{
:slug => 'projects',
:content => { :name => 'LocomotiveCMS', :description => 'Lorem ipsum' }.merge(options.delete(:content) || {}),
:content_entry => { :name => 'LocomotiveCMS', :description => 'Lorem ipsum' }.merge(options.delete(:content_entry) || {}),
:success_callback => 'http://www.locomotivecms.com/success',
:error_callback => 'http://www.locomotivecms.com/failure'
}.merge(options)

View File

@ -8,18 +8,18 @@ describe Locomotive::Export do
site = FactoryGirl.build('another site')
Locomotive::Site.stubs(:find).returns(site)
project_type = build_project_type(site)
project_type.contents.build(:title => 'Project #1', :description => 'Lorem ipsum', :active => true)
project_type.contents.build(:title => 'Project #2', :description => 'More Lorem ipsum', :active => false)
project_type.entries.build(:title => 'Project #1', :description => 'Lorem ipsum', :active => true)
project_type.entries.build(:title => 'Project #2', :description => 'More Lorem ipsum', :active => false)
team_type = build_team_type(site, project_type)
team_type.contents.build(:name => 'Ben', :projects => project_type.contents, :current_project => project_type.contents.first)
team_type.contents.build(:name => 'Zach', :current_project => project_type.contents.last)
team_type.entries.build(:name => 'Ben', :projects => project_type.entries, :current_project => project_type.entries.first)
team_type.entries.build(:name => 'Zach', :current_project => project_type.entries.last)
@project_data = ::Locomotive::Export.new(site).send(:extract_contents, project_type)
@team_data = ::Locomotive::Export.new(site).send(:extract_contents, team_type)
end
it 'includes the exact number of contents' do
it 'includes the exact number of entries' do
@project_data.size.should == 2
@project_data.collect { |n| n.keys.first }.should == ['Project #1', 'Project #2']
end
@ -41,9 +41,9 @@ describe Locomotive::Export do
def build_project_type(site)
FactoryGirl.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1').tap do |content_type|
content_type.contents_custom_fields.build :label => 'Title', :_alias => 'title', :kind => 'string'
content_type.contents_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text'
content_type.contents_custom_fields.build :label => 'Active', :kind => 'boolean'
content_type.entries_custom_fields.build :label => 'Title', :name => 'title', :type => 'string'
content_type.entries_custom_fields.build :label => 'My Description', :name => 'description', :type => 'text'
content_type.entries_custom_fields.build :label => 'Active', :type => 'boolean'
end
end
@ -51,10 +51,10 @@ describe Locomotive::Export do
Object.send(:remove_const, 'TestProject') rescue nil
klass = Object.const_set('TestProject', Class.new { def self.embedded?; false; end })
content_type = FactoryGirl.build(:content_type, :site => site, :name => 'team', :highlighted_field_name => 'custom_field_1')
content_type.contents_custom_fields.build :label => 'Name', :_alias => 'name', :kind => 'string'
content_type.contents_custom_fields.build :label => 'Projects', :kind => 'has_many', :_alias => 'projects', :target => 'TestProject'
content_type.contents_custom_fields.build :label => 'Bio', :_alias => 'bio', :kind => 'text'
content_type.contents_custom_fields.build :label => 'Current Project', :kind => 'has_one', :_alias => 'current_project', :target => 'TestProject'
content_type.entries_custom_fields.build :label => 'Name', :name => 'name', :type => 'string'
content_type.entries_custom_fields.build :label => 'Projects', :type => 'has_many', :name => 'projects', :target => 'TestProject'
content_type.entries_custom_fields.build :label => 'Bio', :name => 'bio', :type => 'text'
content_type.entries_custom_fields.build :label => 'Current Project', :type => 'has_one', :name => 'current_project', :target => 'TestProject'
content_type
end

View File

@ -22,12 +22,12 @@ describe Locomotive::Import::Job do
it 'adds content types' do
@site.content_types.count.should == 4
content_type = @site.content_types.where(:slug => 'projects').first
content_type.contents_custom_fields.size.should == 9
content_type.entries_custom_fields.size.should == 9
end
it 'replaces the target and the reverse_lookup values by the correct ones in a has_many relationship' do
content_type = @site.content_types.where(:slug => 'clients').first
field = content_type.contents_custom_fields.last
field = content_type.entries_custom_fields.last
field.target.should match /^ContentContentType/
field.reverse_lookup.should == 'custom_field_8'
end
@ -44,9 +44,9 @@ describe Locomotive::Import::Job do
it 'adds samples coming with content types' do
content_type = @site.content_types.where(:slug => 'projects').first
content_type.contents.size.should == 5
content_type.entries.size.should == 5
content = content_type.contents.first
content = content_type.entries.first
content._permalink.should == 'locomotivecms'
content.seo_title.should == 'My open source CMS'
content.meta_description.should == 'bla bla bla'

View File

@ -5,9 +5,9 @@ describe Locomotive::Liquid::Drops::Content do
before(:each) do
@site = FactoryGirl.build(:site)
content_type = FactoryGirl.build(:content_type)
content_type.contents_custom_fields.build :label => 'anything', :kind => 'string'
content_type.contents_custom_fields.build :label => 'published_at', :kind => 'date'
@content = content_type.contents.build({
content_type.entries_custom_fields.build :label => 'anything', :type => 'string'
content_type.entries_custom_fields.build :label => 'published_at', :type => 'date'
@content = content_type.entries.build({
:meta_keywords => 'Libidinous, Angsty',
:meta_description => "Quite the combination.",
:published_at => Date.today })

View File

@ -14,9 +14,9 @@ describe Locomotive::Liquid::Drops::Contents do
describe '#group_by' do
it 'orders contents' do
it 'orders entries' do
@site.content_types.stubs(:where).returns([@content_type])
@content_type.contents.klass.expects(:group_by_category).with(:ordered_contents)
@content_type.entries.klass.expects(:group_by_select_option).with(:ordered_entries)
render_template '{% for group in contents.projects.group_by_category %} {{ group.name }} {% endfor %}'
end
@ -52,9 +52,9 @@ describe Locomotive::Liquid::Drops::Contents do
def populate_content_type
@content_type.order_by = :_slug
@content_type.contents.build(:_slug => 'item1')
@content_type.contents.build(:_slug => 'item2')
@content_type.contents.build(:_slug => 'item3')
@content_type.entries.build(:_slug => 'item1')
@content_type.entries.build(:_slug => 'item2')
@content_type.entries.build(:_slug => 'item3')
end
end

View File

@ -73,18 +73,18 @@ describe Locomotive::Liquid::Drops::Page do
it 'renders the content instance highlighted field instead for a templatized page' do
templatized = FactoryGirl.build(:page, :title => 'Lorem ipsum template', :templatized => true)
content_instance = Locomotive::Liquid::Drops::Content.new(mock('content_instance', :highlighted_field_value => 'Locomotive rocks !'))
content_entry = Locomotive::Liquid::Drops::Content.new(mock('content_entry', :highlighted_field_value => 'Locomotive rocks !'))
render_template('{{ page.title }}', 'page' => templatized, 'content_instance' => content_instance).should == 'Locomotive rocks !'
render_template('{{ page.title }}', 'page' => templatized, 'content_entry' => content_entry).should == 'Locomotive rocks !'
end
end
describe 'published?' do
subject { render_template('{{ home.published? }}') }
it { should == @home.published?.to_s }
end
describe 'listed?' do
subject { render_template('{{ home.listed? }}') }
it { should == @home.listed?.to_s }

View File

@ -81,32 +81,32 @@ describe Locomotive::Liquid::Tags::SEO do
let(:content_type) do
FactoryGirl.build(:content_type, :site => site).tap do |ct|
ct.contents_custom_fields.build :label => 'anything', :kind => 'String'
ct.entries_custom_fields.build :label => 'anything', :type => 'String'
end
end
context "has seo title" do
let(:content) { content_type.contents.build(:seo_title => 'Content title (SEO)', :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") }
subject { render_seo_title('content_instance' => content) }
let(:content_entry) { content_type.entries.build(:seo_title => 'Content title (SEO)', :meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") }
subject { render_seo_title('content_entry' => content_entry) }
it { should include(%Q[<title>Content title (SEO)</title>]) }
end
context "does not have seo title" do
let(:content) { content_type.contents.build }
subject { render_seo_title('content_instance' => content) }
let(:content_entry) { content_type.entries.build }
subject { render_seo_title('content_entry' => content_entry) }
it { should include(%Q[<title>Site title (SEO)</title>]) }
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}" />]) }
let(:content_entry) { content_type.entries.build(:meta_keywords => 'Libidinous, Angsty', :meta_description => "Quite the combination.") }
subject { render_seo_metadata('content_entry' => content_entry) }
it { should include(%Q[<meta name="keywords" content="#{content_entry.meta_keywords}" />]) }
it { should include(%Q[<meta name="description" content="#{content_entry.meta_description}" />]) }
end
context "does not have metadata" do
let(:content) { content_type.contents.build }
subject { render_seo_metadata('content_instance' => content) }
let(:content_entry) { content_type.entries.build }
subject { render_seo_metadata('content_entry' => content_entry) }
it { should include(%Q[<meta name="keywords" content="#{site.meta_keywords}" />]) }
it { should include(%Q[<meta name="description" content="#{site.meta_description}" />]) }
end

View File

@ -126,30 +126,30 @@ describe 'Locomotive rendering system' do
before(:each) do
@content_type = FactoryGirl.build(:content_type, :site => nil)
@content = @content_type.contents.build(:_visible => true)
@content_entry = @content_type.entries.build(:_visible => true)
@page.templatized = true
@page.content_type = @content_type
@controller.request.fullpath = '/projects/edeneo.html'
@controller.current_site.pages.expects(:any_in).with({ :fullpath => %w{projects/edeneo projects/content_type_template} }).returns([@page])
end
it 'sets the content_instance variable' do
@content_type.contents.stubs(:where).returns([@content])
it 'sets the content_entry variable' do
@content_type.entries.stubs(:where).returns([@content_entry])
@controller.send(:locomotive_page).should_not be_nil
@controller.instance_variable_get(:@content_instance).should == @content
@controller.instance_variable_get(:@content_entry).should == @content_entry
end
it 'returns the 404 page if the instance does not exist' do
@content_type.contents.stubs(:where).returns([])
@content_type.entries.stubs(:where).returns([])
(klass = Locomotive::Page).expects(:published).returns([true])
@controller.current_site.pages.expects(:not_found).returns(klass)
@controller.send(:locomotive_page).should be_true
@controller.instance_variable_get(:@content_instance).should be_nil
@controller.instance_variable_get(:@content_entry).should be_nil
end
it 'returns the 404 page if the instance is not visible' do
@content._visible = false
@content_type.contents.stubs(:where).returns([@content])
@content_entry._visible = false
@content_type.entries.stubs(:where).returns([@content_entry])
(klass = Locomotive::Page).expects(:published).returns([true])
@controller.current_site.pages.expects(:not_found).returns(klass)
@controller.send(:locomotive_page).should be_true

View File

@ -33,7 +33,7 @@ describe Locomotive::Ability do
context 'content instance' do
subject { Locomotive::ContentInstance.new }
subject { Locomotive::ContentEntry.new }
context 'management' do
it 'should allow management of pages from (admin, designer, author)' do

View File

@ -0,0 +1,209 @@
# encoding: utf-8
require 'spec_helper'
describe Locomotive::ContentEntry do
before(:each) do
Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true)
@content_type = FactoryGirl.build(:content_type)
@content_type.entries_custom_fields.build :label => 'Title', :type => 'String'
@content_type.entries_custom_fields.build :label => 'Description', :type => 'Text'
@content_type.entries_custom_fields.build :label => 'Visible ?', :type => 'Text', :name => 'visible'
@content_type.highlighted_field_name = 'custom_field_1'
end
describe '#validation' do
it 'is valid' do
build_content_entry.should be_valid
end
## Validations ##
it 'requires the presence of title' do
content_entry = build_content_entry_entry :title => nil
content_entry.should_not be_valid
content_entry.errors[:title].should == ["can't be blank"]
end
it 'requires the presence of the permalink (_slug)' do
content_entry = build_content_entry_entry :title => nil
content_entry.should_not be_valid
content_entry.errors[:_slug].should == ["can't be blank"]
end
end
context 'setting the slug' do
before :each do
build_content_entry(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs'
end
it 'uses the given slug if it is unique' do
build_content_entry(:_slug => 'monkeys').tap(&:save!)._slug.should == 'monkeys'
build_content_entry(:_slug => 'cats-2').tap(&:save!)._slug.should == 'cats-2'
end
it 'appends a number to the end of the slug if it is not unique' do
build_content_entry(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-1'
build_content_entry(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-2'
build_content_entry(:_slug => 'dogs-2').tap(&:save!)._slug.should == 'dogs-3'
build_content_entry(:_slug => 'dogs-2').tap(&:save!)._slug.should == 'dogs-4'
end
it 'ignores the case of a slug' do
build_content_entry(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-1'
build_content_entry(:_slug => 'DOGS').tap(&:save!)._slug.should == 'dogs-2'
end
it 'correctly handles slugs with multiple numbers' do
build_content_entry(:_slug => 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-2'
build_content_entry(:_slug => 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-3'
build_content_entry(:_slug => 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi'
build_content_entry(:_slug => 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi-1'
end
end
describe "#navigation" do
before(:each) do
%w(first second third).each_with_index do |item,index|
content = build_content_entry({:title => item.to_s})
content._position_in_list = index
instance_variable_set "@#{item}", content
end
end
it 'should find previous item when available' do
@second.previous.custom_field_1.should == "first"
@second.previous._position_in_list.should == 0
end
it 'should find next item when available' do
@second.next.custom_field_1.should == "third"
@second.next._position_in_list.should == 2
end
it 'should return nil when fetching previous item on first in list' do
@first.previous.should == nil
end
it 'should return nil when fetching next item on last in list' do
@third.next.should == nil
end
end
describe '#permalink' do
before(:each) do
@content_entry = build_content_entry
end
it 'has a default value based on the highlighted field' do
@content_entry.send(:set_slug)
@content_entry._permalink.should == 'locomotive'
end
it 'is empty if no value for the highlighted field is provided' do
@content_entry.title = nil; @content_entry.send(:set_slug)
@content_entry._permalink.should be_nil
end
it 'includes dashes instead of white spaces' do
@content_entry.title = 'my content instance'; @content_entry.send(:set_slug)
@content_entry._permalink.should == 'my-content-instance'
end
it 'removes accentued characters' do
@content_entry.title = "une chèvre dans le pré"; @content_entry.send(:set_slug)
@content_entry._permalink.should == 'une-chevre-dans-le-pre'
end
it 'removes dots' do
@content_entry.title = "my.test"; @content_entry.send(:set_slug)
@content_entry._permalink.should == 'my-test'
end
end
describe '#visibility' do
before(:each) do
@content_entry = build_content_entry
end
it 'is visible by default' do
@content_entry._visible?.should be_true
@content_entry.visible?.should be_true
end
it 'can be visible even if it is nil' do
@content_entry.visible = nil
@content_entry.send(:set_visibility)
@content_entry.visible?.should be_true
end
it 'can not be visible' do
@content_entry.visible = false
@content_entry.send(:set_visibility)
@content_entry.visible?.should be_false
end
end
describe '#requirements' do
it 'has public access to the highlighted field value' do
build_content_entry.highlighted_field_value.should == 'Locomotive'
end
end
describe '#api' do
before(:each) do
@account_1 = FactoryGirl.build('admin user', :id => fake_bson_id('1'))
@account_2 = FactoryGirl.build('frenchy user', :id => fake_bson_id('2'))
@content_type.api_enabled = true
@content_type.api_accounts = ['', @account_1.id, @account_2.id]
Locomotive::Site.any_instance.stubs(:accounts).returns([@account_1, @account_2])
@content_entry = build_content_entry
end
it 'does not send email notifications if the api is disabled' do
@content_type.api_enabled = false
Locomotive::Notifications.expects(:new_content_entry).never
@content_entry.save
end
it 'does not send email notifications if no api accounts' do
@content_type.api_accounts = nil
Locomotive::Notifications.expects(:new_content_entry).never
@content_entry.save
end
it 'sends email notifications when a new instance is created' do
Locomotive::Notifications.expects(:new_content_entry).with(@account_1, @content).returns(mock('mailer', :deliver => true))
Locomotive::Notifications.expects(:new_content_entry).with(@account_2, @content).returns(mock('mailer', :deliver => true))
@content_entry.save
end
end
describe '#site' do
it 'delegates to the content type' do
@content_type.expects(:site)
build_content_entry.site
end
end
def build_content_entry(options = {})
@content_type.entries.build({ :title => 'Locomotive', :description => 'Lorem ipsum....' }.merge(options))
end
def fake_bson_id(id)
BSON::ObjectId(id.to_s.rjust(24, '0'))
end
end

View File

@ -1,209 +0,0 @@
# encoding: utf-8
require 'spec_helper'
describe Locomotive::ContentInstance do
before(:each) do
Locomotive::Site.any_instance.stubs(:create_default_pages!).returns(true)
@content_type = FactoryGirl.build(:content_type)
@content_type.contents_custom_fields.build :label => 'Title', :kind => 'String'
@content_type.contents_custom_fields.build :label => 'Description', :kind => 'Text'
@content_type.contents_custom_fields.build :label => 'Visible ?', :kind => 'Text', :_alias => 'visible'
@content_type.highlighted_field_name = 'custom_field_1'
end
describe '#validation' do
it 'is valid' do
build_content.should be_valid
end
## Validations ##
it 'requires the presence of title' do
content = build_content :title => nil
content.should_not be_valid
content.errors[:title].should == ["can't be blank"]
end
it 'requires the presence of the permalink (_slug)' do
content = build_content :title => nil
content.should_not be_valid
content.errors[:_slug].should == ["can't be blank"]
end
end
context 'setting the slug' do
before :each do
build_content(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs'
end
it 'uses the given slug if it is unique' do
build_content(:_slug => 'monkeys').tap(&:save!)._slug.should == 'monkeys'
build_content(:_slug => 'cats-2').tap(&:save!)._slug.should == 'cats-2'
end
it 'appends a number to the end of the slug if it is not unique' do
build_content(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-1'
build_content(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-2'
build_content(:_slug => 'dogs-2').tap(&:save!)._slug.should == 'dogs-3'
build_content(:_slug => 'dogs-2').tap(&:save!)._slug.should == 'dogs-4'
end
it 'ignores the case of a slug' do
build_content(:_slug => 'dogs').tap(&:save!)._slug.should == 'dogs-1'
build_content(:_slug => 'DOGS').tap(&:save!)._slug.should == 'dogs-2'
end
it 'correctly handles slugs with multiple numbers' do
build_content(:_slug => 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-2'
build_content(:_slug => 'fish-1-2').tap(&:save!)._slug.should == 'fish-1-3'
build_content(:_slug => 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi'
build_content(:_slug => 'fish-1-hi').tap(&:save!)._slug.should == 'fish-1-hi-1'
end
end
describe "#navigation" do
before(:each) do
%w(first second third).each_with_index do |item,index|
content = build_content({:title => item.to_s})
content._position_in_list = index
instance_variable_set "@#{item}", content
end
end
it 'should find previous item when available' do
@second.previous.custom_field_1.should == "first"
@second.previous._position_in_list.should == 0
end
it 'should find next item when available' do
@second.next.custom_field_1.should == "third"
@second.next._position_in_list.should == 2
end
it 'should return nil when fetching previous item on first in list' do
@first.previous.should == nil
end
it 'should return nil when fetching next item on last in list' do
@third.next.should == nil
end
end
describe '#permalink' do
before(:each) do
@content = build_content
end
it 'has a default value based on the highlighted field' do
@content.send(:set_slug)
@content._permalink.should == 'locomotive'
end
it 'is empty if no value for the highlighted field is provided' do
@content.title = nil; @content.send(:set_slug)
@content._permalink.should be_nil
end
it 'includes dashes instead of white spaces' do
@content.title = 'my content instance'; @content.send(:set_slug)
@content._permalink.should == 'my-content-instance'
end
it 'removes accentued characters' do
@content.title = "une chèvre dans le pré"; @content.send(:set_slug)
@content._permalink.should == 'une-chevre-dans-le-pre'
end
it 'removes dots' do
@content.title = "my.test"; @content.send(:set_slug)
@content._permalink.should == 'my-test'
end
end
describe '#visibility' do
before(:each) do
@content = build_content
end
it 'is visible by default' do
@content._visible?.should be_true
@content.visible?.should be_true
end
it 'can be visible even if it is nil' do
@content.visible = nil
@content.send(:set_visibility)
@content.visible?.should be_true
end
it 'can not be visible' do
@content.visible = false
@content.send(:set_visibility)
@content.visible?.should be_false
end
end
describe '#requirements' do
it 'has public access to the highlighted field value' do
build_content.highlighted_field_value.should == 'Locomotive'
end
end
describe '#api' do
before(:each) do
@account_1 = FactoryGirl.build('admin user', :id => fake_bson_id('1'))
@account_2 = FactoryGirl.build('frenchy user', :id => fake_bson_id('2'))
@content_type.api_enabled = true
@content_type.api_accounts = ['', @account_1.id, @account_2.id]
Locomotive::Site.any_instance.stubs(:accounts).returns([@account_1, @account_2])
@content = build_content
end
it 'does not send email notifications if the api is disabled' do
@content_type.api_enabled = false
Locomotive::Notifications.expects(:new_content_instance).never
@content.save
end
it 'does not send email notifications if no api accounts' do
@content_type.api_accounts = nil
Locomotive::Notifications.expects(:new_content_instance).never
@content.save
end
it 'sends email notifications when a new instance is created' do
Locomotive::Notifications.expects(:new_content_instance).with(@account_1, @content).returns(mock('mailer', :deliver => true))
Locomotive::Notifications.expects(:new_content_instance).with(@account_2, @content).returns(mock('mailer', :deliver => true))
@content.save
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))
end
def fake_bson_id(id)
BSON::ObjectId(id.to_s.rjust(24, '0'))
end
end

View File

@ -10,7 +10,7 @@ describe Locomotive::ContentType do
it 'should have a valid factory' do
content_type = FactoryGirl.build(:content_type)
content_type.contents_custom_fields.build :label => 'anything', :kind => 'String'
content_type.entries_custom_fields.build :label => 'anything', :type => 'String'
content_type.should be_valid
end
@ -32,7 +32,7 @@ describe Locomotive::ContentType do
it 'is not valid if slug is not unique' do
content_type = FactoryGirl.build(:content_type)
content_type.contents_custom_fields.build :label => 'anything', :kind => 'String'
content_type.entries_custom_fields.build :label => 'anything', :type => 'String'
content_type.save
(content_type = FactoryGirl.build(:content_type, :site => content_type.site)).should_not be_valid
content_type.errors[:slug].should == ["is already taken"]
@ -41,27 +41,27 @@ describe Locomotive::ContentType do
it 'is not valid if there is not at least one field' do
content_type = FactoryGirl.build(:content_type)
content_type.should_not be_valid
content_type.errors[:contents_custom_fields].should == ["is too small (minimum element number is 1)"]
content_type.errors[:entries_custom_fields].should == ["is too small (minimum element number is 1)"]
end
%w(created_at updated_at).each do |_alias|
it "does not allow #{_alias} as alias" do
%w(created_at updated_at).each do |name|
it "does not allow #{name} as name" do
content_type = FactoryGirl.build(:content_type)
field = content_type.contents_custom_fields.build :label => 'anything', :kind => 'String', :_alias => _alias
field = content_type.entries_custom_fields.build :label => 'anything', :type => 'String', :name => name
field.valid?.should be_false
field.errors[:_alias].should == ['is reserved']
field.errors[:name].should == ['is reserved']
end
end
end
context '#ordered_contents' do
context '#ordered_entries' do
before(:each) do
@content_type = FactoryGirl.build(:content_type, :order_by => 'created_at')
@content_1 = stub('content_1', :name => 'Did', :_position_in_list => 2)
@content_2 = stub('content_2', :name => 'Sacha', :_position_in_list => 1)
@content_type.stubs(:contents).returns([@content_1, @content_2])
@content_type.stubs(:entries).returns([@content_1, @content_2])
end
it 'orders with the ASC direction by default' do
@ -74,34 +74,34 @@ describe Locomotive::ContentType do
@content_type.order_manually?.should == true
end
it 'returns a list of contents ordered manually' do
it 'returns a list of entries ordered manually' do
@content_type.order_by = '_position_in_list'
@content_type.ordered_contents.collect(&:name).should == %w(Sacha Did)
@content_type.ordered_entries.collect(&:name).should == %w(Sacha Did)
end
it 'returns a list of contents ordered by a column specified by order_by (ASC)' do
it 'returns a list of entries ordered by a column specified by order_by (ASC)' do
@content_type.order_by = 'name'
@content_type.ordered_contents.collect(&:name).should == %w(Did Sacha)
@content_type.ordered_entries.collect(&:name).should == %w(Did Sacha)
end
it 'returns a list of contents ordered by a column specified by order_by (DESC)' do
it 'returns a list of entries ordered by a column specified by order_by (DESC)' do
@content_type.order_by = 'name'
@content_type.order_direction = 'desc'
@content_type.ordered_contents.collect(&:name).should == %w(Sacha Did)
@content_type.ordered_entries.collect(&:name).should == %w(Sacha Did)
end
it 'returns a list of contents ordered by a Date column when first instance is missing the value' do
it 'returns a list of entries ordered by a Date column when first instance is missing the value' do
@content_type = FactoryGirl.build(:content_type, :order_by => 'created_at')
@content_type.content_custom_fields.build :label => 'Active at', :name => 'active_at', :kind => 'Date'
@content_type.content_custom_fields.build :label => 'Active at', :name => 'active_at', :type => 'Date'
e = Date.parse('01/01/2001')
l = Date.parse('02/02/2002')
[nil,e,l].each { |d| @content_type.contents << @content_type.content_klass.new(:active_at => d) }
[nil,e,l].each { |d| @content_type.entries << @content_type.content_klass.new(:active_at => d) }
@content_type.order_by = 'active_at'
@content_type.order_direction = 'asc'
lambda { @content_type.ordered_contents }.should_not raise_error(ArgumentError)
@content_type.ordered_contents.map(&:active_at).should == [nil,e,l]
lambda { @content_type.ordered_entries }.should_not raise_error(ArgumentError)
@content_type.ordered_entries.map(&:active_at).should == [nil,e,l]
@content_type.order_direction = 'desc'
@content_type.ordered_contents.map(&:active_at).should == [l,e,nil]
@content_type.ordered_entries.map(&:active_at).should == [l,e,nil]
end
end
@ -112,8 +112,8 @@ describe Locomotive::ContentType do
site = FactoryGirl.build(:site)
Locomotive::Site.stubs(:find).returns(site)
@content_type = FactoryGirl.build(:content_type, :site => site, :highlighted_field_name => 'custom_field_1')
@content_type.contents_custom_fields.build :label => 'My Description', :_alias => 'description', :kind => 'text'
@content_type.contents_custom_fields.build :label => 'Active', :kind => 'boolean'
@content_type.entries_custom_fields.build :label => 'My Description', :name => 'description', :type => 'text'
@content_type.entries_custom_fields.build :label => 'Active', :type => 'boolean'
# Locomotive::ContentType.logger = Logger.new($stdout)
# Locomotive::ContentType.db.connection.instance_variable_set(:@logger, Logger.new($stdout))
end
@ -121,7 +121,7 @@ describe Locomotive::ContentType do
context 'unit' do
before(:each) do
@field = CustomFields::Field.new(:kind => 'String')
@field = CustomFields::Field.new(:type => 'String')
end
it 'should tell if it is a String' do
@ -129,7 +129,7 @@ describe Locomotive::ContentType do
end
it 'should tell if it is a Text' do
@field.kind = 'Text'
@field.type = 'Text'
@field.text?.should be_true
end
@ -137,24 +137,24 @@ describe Locomotive::ContentType do
context 'validation' do
%w{label kind}.each do |key|
%w{label type}.each do |key|
it "should validate presence of #{key}" do
field = @content_type.contents_custom_fields.build({ :label => 'Shortcut', :kind => 'String' }.merge(key.to_sym => nil))
field = @content_type.entries_custom_fields.build({ :label => 'Shortcut', :type => 'String' }.merge(key.to_sym => nil))
field.should_not be_valid
field.errors[key.to_sym].should == ["can't be blank"]
end
end
it 'should not have unique label' do
field = @content_type.contents_custom_fields.build :label => 'Active', :kind => 'Boolean'
field = @content_type.entries_custom_fields.build :label => 'Active', :type => 'Boolean'
field.should_not be_valid
field.errors[:label].should == ["is already taken"]
end
it 'should invalidate parent if custom field is not valid' do
field = @content_type.contents_custom_fields.build
field = @content_type.entries_custom_fields.build
@content_type.should_not be_valid
@content_type.contents_custom_fields.last.errors[:label].should == ["can't be blank"]
@content_type.entries_custom_fields.last.errors[:label].should == ["can't be blank"]
end
end
@ -162,13 +162,13 @@ describe Locomotive::ContentType do
context 'define core attributes' do
it 'should have an unique name' do
@content_type.contents_custom_fields.first._name.should == "custom_field_1"
@content_type.contents_custom_fields.last._name.should == "custom_field_2"
@content_type.entries_custom_fields.first._name.should == "custom_field_1"
@content_type.entries_custom_fields.last._name.should == "custom_field_2"
end
it 'should have an unique alias' do
@content_type.contents_custom_fields.first.safe_alias.should == "description"
@content_type.contents_custom_fields.last.safe_alias.should == "active"
@content_type.entries_custom_fields.first.name.should == "description"
@content_type.entries_custom_fields.last.name.should == "active"
end
end
@ -176,7 +176,7 @@ describe Locomotive::ContentType do
context 'build and save' do
it 'should build asset' do
asset = @content_type.contents.build
asset = @content_type.entries.build
lambda {
asset.description
asset.active
@ -185,24 +185,24 @@ describe Locomotive::ContentType do
end
it 'should assign values to newly built asset' do
asset = build_content(@content_type)
asset = build_content_entry(@content_type)
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should save asset' do
asset = build_content(@content_type)
asset = build_content_entry(@content_type)
asset.save and @content_type.reload
asset = @content_type.contents.first
asset = @content_type.entries.first
asset.description.should == 'Lorem ipsum'
asset.active.should == true
end
it 'should not modify contents from another collection' do
asset = build_content(@content_type)
it 'should not modify entries from another collection' do
asset = build_content_entry(@content_type)
asset.save and @content_type.reload
new_collection = Locomotive::ContentType.new
lambda { new_collection.contents.build.description }.should raise_error
lambda { new_collection.entries.build.description }.should raise_error
end
end
@ -210,36 +210,36 @@ describe Locomotive::ContentType do
context 'modifying fields' do
before(:each) do
@asset = build_content(@content_type).save
@asset = build_content_entry(@content_type).save
end
it 'should add new field' do
@content_type.contents_custom_fields.build :label => 'Active at', :name => 'active_at', :kind => 'Date'
@content_type.entries_custom_fields.build :label => 'Active at', :name => 'active_at', :type => 'Date'
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
asset = @content_type.entries.first
lambda { asset.active_at }.should_not raise_error
end
it 'should remove field' do
@content_type.contents_custom_fields.clear
@content_type.entries_custom_fields.clear
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
asset = @content_type.entries.first
lambda { asset.active_at }.should raise_error
end
it 'should rename field label' do
@content_type.contents_custom_fields.first.label = 'Simple description'
@content_type.contents_custom_fields.first._alias = nil
@content_type.entries_custom_fields.first.label = 'Simple description'
@content_type.entries_custom_fields.first.name = nil
@content_type.upsert(:validate => false)
@content_type.invalidate_content_klass
@content_type.reload
asset = @content_type.contents.first
asset = @content_type.entries.first
asset.simple_description.should == 'Lorem ipsum'
end
@ -248,38 +248,38 @@ describe Locomotive::ContentType do
context 'managing from hash' do
it 'adds new field' do
@content_type.contents_custom_fields.clear
field = @content_type.contents_custom_fields.build :label => 'Title'
@content_type.contents_custom_fields_attributes = { 0 => { :id => field.id.to_s, 'label' => 'A title', 'kind' => 'String' }, 1 => { 'label' => 'Tagline', 'kind' => 'String' } }
@content_type.contents_custom_fields.size.should == 2
@content_type.contents_custom_fields.first.label.should == 'A title'
@content_type.contents_custom_fields.last.label.should == 'Tagline'
@content_type.entries_custom_fields.clear
field = @content_type.entries_custom_fields.build :label => 'Title'
@content_type.entries_custom_fields_attributes = { 0 => { :id => field.id.to_s, 'label' => 'A title', 'type' => 'String' }, 1 => { 'label' => 'Tagline', 'type' => 'String' } }
@content_type.entries_custom_fields.size.should == 2
@content_type.entries_custom_fields.first.label.should == 'A title'
@content_type.entries_custom_fields.last.label.should == 'Tagline'
end
it 'updates/removes fields' do
field = @content_type.contents_custom_fields.build :label => 'Title', :kind => 'String'
field = @content_type.entries_custom_fields.build :label => 'Title', :type => 'String'
@content_type.save; @content_type = Locomotive::ContentType.find(@content_type.id)
@content_type.update_attributes(:contents_custom_fields_attributes => {
'0' => { 'id' => lookup_field_id(0), 'label' => 'My Description', 'kind' => 'Text', '_destroy' => '1' },
'1' => { 'id' => lookup_field_id(1), 'label' => 'Active', 'kind' => 'Boolean', '_destroy' => '1' },
'2' => { 'id' => lookup_field_id(2), 'label' => 'My Title !', 'kind' => 'String' },
'new_record' => { 'label' => 'Published at', 'kind' => 'String' }
@content_type.update_attributes(:entries_custom_fields_attributes => {
'0' => { 'id' => lookup_field_id(0), 'label' => 'My Description', 'type' => 'Text', '_destroy' => '1' },
'1' => { 'id' => lookup_field_id(1), 'label' => 'Active', 'type' => 'Boolean', '_destroy' => '1' },
'2' => { 'id' => lookup_field_id(2), 'label' => 'My Title !', 'type' => 'String' },
'new_record' => { 'label' => 'Published at', 'type' => 'String' }
})
@content_type = Locomotive::ContentType.find(@content_type.id)
@content_type.contents_custom_fields.size.should == 2
@content_type.contents_custom_fields.first.label.should == 'My Title !'
@content_type.entries_custom_fields.size.should == 2
@content_type.entries_custom_fields.first.label.should == 'My Title !'
end
end
end
def build_content(content_type)
content_type.contents.build(:name => 'Asset on steroids', :description => 'Lorem ipsum', :active => true)
def build_content_entry(content_type)
content_type.entries.build(:name => 'Asset on steroids', :description => 'Lorem ipsum', :active => true)
end
def lookup_field_id(index)
@content_type.contents_custom_fields.all[index].id.to_s
@content_type.entries_custom_fields.all[index].id.to_s
end
end

View File

@ -138,7 +138,7 @@ FactoryGirl.define do
site { Locomotive::Site.where(:subdomain => "acme").first || Factory(:site) }
end
factory :content_instance, :class => Locomotive::ContentInstance do
factory :content_entry, :class => Locomotive::ContentEntry do
end
end