minimal version of the new UI for content types
This commit is contained in:
commit
00283993c0
4
Gemfile
4
Gemfile
@ -13,8 +13,8 @@ gem 'bson_ext', '~> 1.4.0'
|
||||
gem 'mongoid', '~> 2.3.3'
|
||||
gem 'locomotive_mongoid_acts_as_tree', :git => 'git@github.com:locomotivecms/mongoid_acts_as_tree.git'
|
||||
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git'
|
||||
# gem 'custom_fields', :path => '../gems/custom_fields' # DEV
|
||||
gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental'
|
||||
gem 'custom_fields', :path => '../gems/custom_fields' # DEV
|
||||
# gem 'custom_fields', :git => 'git://github.com/locomotivecms/custom_fields.git', :branch => 'experimental'
|
||||
gem 'kaminari'
|
||||
|
||||
gem 'haml', '~> 3.1.3'
|
||||
|
18
Gemfile.lock
18
Gemfile.lock
@ -7,16 +7,6 @@ GIT
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/locomotivecms/custom_fields.git
|
||||
revision: 9cc4a3ca7e2306a59a9ad0c8a837a35d8fc5dfc6
|
||||
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:
|
||||
|
BIN
app/assets/images/locomotive/list/icons/toggle.png
Normal file
BIN
app/assets/images/locomotive/list/icons/toggle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 347 B |
BIN
app/assets/images/locomotive/list/icons/toggle_off.png
Normal file
BIN
app/assets/images/locomotive/list/icons/toggle_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 346 B |
@ -13,7 +13,8 @@ class Locomotive.Models.ContentType extends Backbone.Model
|
||||
|
||||
toJSON: ->
|
||||
_.tap super, (hash) =>
|
||||
hash.contents_custom_fields = @get('contents_custom_fields').toJSONForSave() if @get('contents_custom_fields')
|
||||
delete hash.contents_custom_fields
|
||||
hash.contents_custom_fields_attributes = @get('contents_custom_fields').toJSONForSave() if @get('contents_custom_fields')
|
||||
|
||||
class Locomotive.Models.ContentTypesCollection extends Backbone.Collection
|
||||
|
||||
|
@ -21,13 +21,25 @@ class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.For
|
||||
|
||||
@render_custom_fields()
|
||||
|
||||
@slugify_name() # slugify the slug field from name
|
||||
|
||||
return @
|
||||
|
||||
render_custom_fields: ->
|
||||
@custom_fields_view = new Locomotive.Views.ContentTypes.CustomFieldsView model: @model #, errors: @options.errors
|
||||
@custom_fields_view = new Locomotive.Views.ContentTypes.CustomFieldsView model: @model
|
||||
|
||||
@$('#custom_fields_input').append(@custom_fields_view.render().el)
|
||||
|
||||
slugify_name: ->
|
||||
@$('#content_type_name').slugify(target: @$('#content_type_slug'), sep: '_')
|
||||
|
||||
show_error: (attribute, message, html) ->
|
||||
if attribute == 'contents_custom_fields'
|
||||
for _message, index in message
|
||||
@custom_fields_view._entry_views[index].show_error(_message[0])
|
||||
else
|
||||
super
|
||||
|
||||
remove: ->
|
||||
@custom_fields_view.remove()
|
||||
super
|
||||
|
@ -7,7 +7,7 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
||||
className: 'custom-field'
|
||||
|
||||
events:
|
||||
'click a.edit': 'toggle_form'
|
||||
'click a.toggle': 'toggle'
|
||||
'click a.remove': 'remove'
|
||||
|
||||
render: ->
|
||||
@ -15,9 +15,11 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
||||
|
||||
Backbone.ModelBinding.bind @, all: 'class'
|
||||
|
||||
@$('span.label-input input[type=text], span.type-input select').editableField()
|
||||
|
||||
return @
|
||||
|
||||
toggle_form: (event) ->
|
||||
toggle: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
form = @$('ol')
|
||||
|
||||
@ -26,10 +28,14 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
||||
else
|
||||
form.slideUp()
|
||||
|
||||
show_error: (message) ->
|
||||
html = $("<span class=\"inline-errors\">#{message}</div>")
|
||||
@$('span.required-input').after(html)
|
||||
|
||||
remove: (event) ->
|
||||
event.stopPropagation() & event.preventDefault()
|
||||
|
||||
if confirm($(event.target).attr('data-confirm'))
|
||||
# @$('input[type=text]').editableField('destroy')
|
||||
@$('span.label-input input[type=text], span.type-input select').editableField('destroy')
|
||||
super()
|
||||
@options.parent_view.remove_entry(@model, @)
|
@ -72,9 +72,18 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
|
||||
if @model.get('contents_custom_fields').length == 0
|
||||
@$('.empty').show()
|
||||
else
|
||||
_.each @model.get('contents_custom_fields'), (custom_field) =>
|
||||
@model.get('contents_custom_fields').each (custom_field) =>
|
||||
@_insert_entry(custom_field)
|
||||
|
||||
_insert_entry: (custom_field) ->
|
||||
view = new Locomotive.Views.ContentTypes.CustomFieldEntryView model: custom_field, parent_view: @
|
||||
|
||||
(@_entry_views ||= []).push(view)
|
||||
|
||||
@$('ul').append(view.render().el)
|
||||
|
||||
@refresh_position_entries()
|
||||
|
||||
#
|
||||
# show_errors: ->
|
||||
# _.each @options.errors.domain || [], (message) => @show_error(message)
|
||||
@ -85,11 +94,4 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
|
||||
# html = $('<span></span>').addClass('inline-errors').html(message)
|
||||
# view.$('input[type=text].path').after(html)
|
||||
|
||||
_insert_entry: (custom_field) ->
|
||||
view = new Locomotive.Views.ContentTypes.CustomFieldEntryView model: custom_field, parent_view: @
|
||||
|
||||
(@_entry_views ||= []).push(view)
|
||||
|
||||
@$('ul').append(view.render().el)
|
||||
|
||||
@refresh_position_entries()
|
||||
|
@ -0,0 +1,6 @@
|
||||
Locomotive.Views.ContentTypes ||= {}
|
||||
|
||||
class Locomotive.Views.ContentTypes.EditView extends Locomotive.Views.ContentTypes.FormView
|
||||
|
||||
save: (event) ->
|
||||
@save_in_ajax event
|
@ -75,6 +75,9 @@ class Locomotive.Views.Shared.FormView extends Backbone.View
|
||||
|
||||
show_errors: (errors) ->
|
||||
for attribute, message of errors
|
||||
if _.isArray(message[0])
|
||||
@show_error attribute, message
|
||||
else
|
||||
html = $("<div class=\"inline-errors\"><p>#{message[0]}</p></div>")
|
||||
@show_error attribute, message[0], html
|
||||
|
||||
|
@ -60,13 +60,17 @@ form.formtastic {
|
||||
.list {
|
||||
.empty {
|
||||
text-align: left;
|
||||
color: #BDBFC9;
|
||||
text-shadow: #fff 1px 1px 1px;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
li, .entry, .new-entry {
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
height: 31px;
|
||||
line-height: 31px;
|
||||
|
||||
padding: 0 10px;
|
||||
|
||||
@ -118,7 +122,7 @@ form.formtastic {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
a.remove {
|
||||
a.remove, a.toggle {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@ -127,15 +131,22 @@ form.formtastic {
|
||||
top: 4px;
|
||||
|
||||
outline: none;
|
||||
|
||||
background: transparent image-url("locomotive/list/icons/trash_off.png") repeat 0 0;
|
||||
|
||||
text-indent: -9999px;
|
||||
|
||||
&.remove {
|
||||
background: transparent image-url("locomotive/list/icons/trash_off.png") repeat 0 0;
|
||||
&:hover {
|
||||
background-image: image-url("locomotive/list/icons/trash.png");
|
||||
}
|
||||
}
|
||||
|
||||
&.toggle {
|
||||
background: transparent image-url("locomotive/list/icons/toggle_off.png") repeat 0 0;
|
||||
&:hover {
|
||||
background-image: image-url("locomotive/list/icons/toggle.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@ -382,7 +393,7 @@ form.formtastic {
|
||||
}
|
||||
|
||||
&.editable {
|
||||
background-image: image-url("locomotive//icons/membership_edit.png");
|
||||
background-image: image-url("locomotive/icons/membership_edit.png");
|
||||
background-position: 0px 3px;
|
||||
}
|
||||
}
|
||||
@ -427,8 +438,119 @@ form.formtastic {
|
||||
}
|
||||
} // > li#account_sites_input
|
||||
|
||||
&#custom_fields_input {
|
||||
|
||||
padding-top: 10px;
|
||||
|
||||
li.custom-field {
|
||||
height: auto;
|
||||
|
||||
.editable {
|
||||
display: inline-block;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
span.handle {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
span.label-input {
|
||||
input[type=text] {
|
||||
float: none;
|
||||
display: inline;
|
||||
|
||||
@include default-input-style;
|
||||
margin-left: 5px;
|
||||
padding: 2px 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.editable {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
span.type-input {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
|
||||
.editable {
|
||||
// font-style: italic;
|
||||
color: #585A69;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
span.required-input {
|
||||
margin-left: 10px;
|
||||
|
||||
label {
|
||||
float: none;
|
||||
width: auto;
|
||||
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
} // li.custom-field
|
||||
|
||||
.new-entry {
|
||||
|
||||
input[type=text] {
|
||||
@include default-input-style;
|
||||
margin-left: 5px;
|
||||
padding: 2px 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
} // .new-entry
|
||||
|
||||
} // > li#custom_fields_input
|
||||
|
||||
} // > li
|
||||
|
||||
&.nested {
|
||||
width: 858px;
|
||||
border: none;
|
||||
@include border-radius(0);
|
||||
@include box-shadow(transparent 0 0 0 0);
|
||||
background: transparent;
|
||||
|
||||
> li.input {
|
||||
height: auto;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 29px;
|
||||
background: transparent;
|
||||
border-top: 1px solid #CCC;
|
||||
@include border-radius(0);
|
||||
@include box-shadow(transparent 0 0 0 0);
|
||||
|
||||
label.label {
|
||||
width: 174px;
|
||||
padding-top: 0px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
&.string, &.password {
|
||||
input[type=text], input[type=password] {
|
||||
width: 623px;
|
||||
}
|
||||
|
||||
p.inline-hints {
|
||||
margin-top: 0px;
|
||||
}
|
||||
} // li.string, li.password
|
||||
|
||||
p.inline-hints {
|
||||
margin-left: 174px;
|
||||
}
|
||||
|
||||
} // li.input
|
||||
|
||||
} // ol.nested
|
||||
|
||||
} //ol
|
||||
} // fieldset
|
||||
|
||||
|
@ -15,9 +15,7 @@ module Locomotive
|
||||
|
||||
## validations ##
|
||||
validate :require_highlighted_field
|
||||
# validate :validate_uniqueness_of_slug
|
||||
validates_uniqueness_of :_slug, :scope => [:content_type_id]
|
||||
validates_presence_of :_slug
|
||||
validates :_slug, :presence => true, :uniqueness => { :scope => :content_type_id }
|
||||
|
||||
## associations ##
|
||||
belongs_to :site
|
||||
@ -82,9 +80,29 @@ module Locomotive
|
||||
|
||||
protected
|
||||
|
||||
# Sets the slug of the instance by using the value of the highlighted field
|
||||
# (if available). If a sibling content instance has the same permalink then a
|
||||
# unique one will be generated
|
||||
def set_slug
|
||||
self._slug = self.highlighted_field_value.dup if self._slug.blank? && self.highlighted_field_value.present?
|
||||
self._slug.permalink! if self._slug.present?
|
||||
self._slug = highlighted_field_value.dup if _slug.blank? && highlighted_field_value.present?
|
||||
|
||||
if _slug.present?
|
||||
self._slug.permalink!
|
||||
self._slug = next_unique_slug if slug_already_taken?
|
||||
end
|
||||
end
|
||||
|
||||
# Return the next available unique slug as a string
|
||||
def next_unique_slug
|
||||
slug = _slug.gsub(/-\d*$/, '')
|
||||
last_slug = _parent.contents.where(:_id.ne => _id, :_slug => /^#{slug}-?\d*?$/i).order_by(:_slug).last._slug
|
||||
next_number = last_slug.scan(/-(\d)$/).flatten.first.to_i + 1
|
||||
|
||||
[slug, next_number].join('-')
|
||||
end
|
||||
|
||||
def slug_already_taken?
|
||||
_parent.contents.where(:_id.ne => _id, :_slug => _slug).any?
|
||||
end
|
||||
|
||||
def set_visibility
|
||||
@ -109,12 +127,6 @@ module Locomotive
|
||||
end
|
||||
end
|
||||
|
||||
# def validate_uniqueness_of_slug
|
||||
# if self._parent.contents.any? { |c| c._id != self._id && c._slug == self._slug }
|
||||
# self.errors.add(:_slug, :taken)
|
||||
# end
|
||||
# end
|
||||
|
||||
def highlighted_field_alias
|
||||
self.content_type.highlighted_field._alias.to_sym
|
||||
end
|
||||
|
@ -20,12 +20,7 @@ module Locomotive
|
||||
|
||||
## associations ##
|
||||
belongs_to :site, :class_name => 'Locomotive::Site'
|
||||
has_many :contents, :class_name => 'Locomotive::ContentInstance'
|
||||
# embeds_many :contents, :class_name => 'Locomotive::ContentInstance', :validate => false do
|
||||
# def visible
|
||||
# @target.find_all { |c| c.visible? }
|
||||
# end
|
||||
# end
|
||||
has_many :contents, :class_name => 'Locomotive::ContentInstance', :dependent => :destroy
|
||||
|
||||
## named scopes ##
|
||||
scope :ordered, :order_by => :updated_at.desc
|
||||
@ -35,6 +30,7 @@ module Locomotive
|
||||
|
||||
## callbacks ##
|
||||
before_validation :normalize_slug
|
||||
after_validation :bubble_fields_errors_up
|
||||
before_save :set_default_values
|
||||
# after_destroy :remove_uploaded_files
|
||||
|
||||
@ -60,6 +56,14 @@ module Locomotive
|
||||
self.order_direction.blank? || self.order_direction == 'asc'
|
||||
end
|
||||
|
||||
def to_presenter
|
||||
Locomotive::ContentTypePresenter.new(self)
|
||||
end
|
||||
|
||||
def as_json(options = {})
|
||||
self.to_presenter.as_json
|
||||
end
|
||||
|
||||
# def list_or_group_contents
|
||||
# if self.groupable?
|
||||
# groups = self.contents.klass.send(:"group_by_#{self.group_by_field._alias}", :ordered_contents)
|
||||
@ -75,11 +79,11 @@ module Locomotive
|
||||
# self.ordered_contents
|
||||
# end
|
||||
# end
|
||||
|
||||
#
|
||||
# def latest_updated_contents
|
||||
# self.contents.latest_updated.reject { |c| !c.persisted? }
|
||||
# end
|
||||
|
||||
#
|
||||
# def ordered_contents(conditions = {})
|
||||
# column = self.order_by.to_sym
|
||||
#
|
||||
@ -103,20 +107,20 @@ module Locomotive
|
||||
# end
|
||||
#
|
||||
# self.contents.where(conditions_with_names)
|
||||
# end).sort { |a, b| (a.send(column) || 0) <=> (b.send(column) || 0) }
|
||||
# end).sort { |a, b| (a.send(column) && b.send(column)) ? (a.send(column) || 0) <=> (b.send(column) || 0) : 0 }
|
||||
#
|
||||
# return list if self.order_manually?
|
||||
#
|
||||
# self.asc_order? ? list : list.reverse
|
||||
# end
|
||||
|
||||
#
|
||||
# def sort_contents!(ids)
|
||||
# ids.each_with_index do |id, position|
|
||||
# self.contents.find(BSON::ObjectId(id))._position_in_list = position
|
||||
# end
|
||||
# self.save
|
||||
# end
|
||||
|
||||
#
|
||||
# def highlighted_field
|
||||
# self.contents_custom_fields.detect { |f| f._name == self.highlighted_field_name }
|
||||
# end
|
||||
@ -129,7 +133,7 @@ module Locomotive
|
||||
|
||||
def set_default_values
|
||||
self.order_by ||= 'created_at'
|
||||
self.highlighted_field_name ||= self.contents_custom_fields.first._name
|
||||
self.highlighted_field_name ||= self.contents_custom_fields.first.name
|
||||
end
|
||||
|
||||
def normalize_slug
|
||||
@ -137,13 +141,16 @@ module Locomotive
|
||||
self.slug.permalink! if self.slug.present?
|
||||
end
|
||||
|
||||
# def remove_uploaded_files # callbacks are not called on each content so we do it manually
|
||||
# self.contents.each do |content|
|
||||
# self.contents_custom_fields.each do |field|
|
||||
# content.send(:"remove_#{field._name}!") if field.kind == 'file'
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
def bubble_fields_errors_up
|
||||
return if self.errors[:contents_custom_fields].empty?
|
||||
|
||||
self.errors.set(:contents_custom_fields, [])
|
||||
|
||||
self.contents_custom_fields.each do |field|
|
||||
next if field.valid?
|
||||
self.errors.add(:contents_custom_fields, field.errors.to_a)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
15
app/presenters/locomotive/content_type_presenter.rb
Normal file
15
app/presenters/locomotive/content_type_presenter.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module Locomotive
|
||||
class ContentTypePresenter < BasePresenter
|
||||
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -17,5 +17,3 @@
|
||||
= render 'form', :f => f
|
||||
|
||||
= render 'locomotive/shared/form_actions', :back_url => contents_url(@content_type.slug_was), :button_label => :update
|
||||
|
||||
= render 'locomotive/custom_fields/edit_field', :content_type => @content_type
|
@ -13,5 +13,3 @@
|
||||
= render 'form', :f => f
|
||||
|
||||
= render 'locomotive/shared/form_actions', :back_url => pages_url, :button_label => :create
|
||||
|
||||
/ = render 'locomotive/custom_fields/edit_field', :content_type => @content_type
|
@ -1,6 +1,6 @@
|
||||
- if breadcrumb_root
|
||||
- title t('.title.breadcrumb', :root => link_to(breadcrumb_root._label, breadcrumb_url), :type => @content_type.name.capitalize)
|
||||
- else
|
||||
/ - if breadcrumb_root
|
||||
/ - title t('.title.breadcrumb', :root => link_to(breadcrumb_root._label, breadcrumb_url), :type => @content_type.name.capitalize)
|
||||
/ - else
|
||||
- title t('.title.default', :type => @content_type.name.capitalize)
|
||||
|
||||
- content_for :submenu do
|
||||
|
@ -23,13 +23,13 @@
|
||||
%span.handle
|
||||
= image_tag 'locomotive/form/icons/drag.png'
|
||||
|
||||
%span.label
|
||||
%span.label-input
|
||||
= g.text_field :label, :class => 'label'
|
||||
|
||||
%span.type
|
||||
%span.type-input
|
||||
= g.select :type, options_for_custom_field_type, {}, { :class => 'type' }
|
||||
|
||||
%span.required
|
||||
%span.required-input
|
||||
= g.check_box :required, :class => 'required'
|
||||
|
||||
= g.label :required, t('.is_required')
|
||||
@ -41,5 +41,5 @@
|
||||
= g.input :hint, :input_html => { :class => 'hint' }
|
||||
|
||||
%span.actions
|
||||
= link_to 'edit', '#', :class => 'edit'
|
||||
= link_to 'toggle', '#', :class => 'toggle'
|
||||
= link_to 'x', '#', :class => 'remove', :confirm => t('locomotive.messages.confirm')
|
@ -12,14 +12,15 @@
|
||||
%span= time_ago_in_words(page.updated_at)
|
||||
|
||||
- each_content_type_menu_item do |content_type|
|
||||
.wrapper
|
||||
.header
|
||||
%p= link_to t('locomotive.contents.index.new'), new_content_url(content_type.slug)
|
||||
|
||||
- if can? :manage, content_type
|
||||
%p.edit= link_to t('locomotive.contents.index.edit'), edit_content_type_url(content_type)
|
||||
|
||||
/ .inner
|
||||
/ %h2!= t('locomotive.contents.index.lastest_items')
|
||||
.inner
|
||||
%h2!= t('locomotive.contents.index.lastest_items')
|
||||
/ %ul
|
||||
/ - content_type.latest_updated_contents.each do |content|
|
||||
/ %li
|
||||
|
@ -5,4 +5,5 @@
|
||||
#
|
||||
require 'formtastic'
|
||||
|
||||
Formtastic::FormBuilder.i18n_lookups_by_default = true
|
||||
Formtastic::FormBuilder.configure :escape_html_entities_in_hints_and_labels, false
|
||||
|
@ -80,10 +80,6 @@ en:
|
||||
source: "The current file is available here %{url}"
|
||||
update:
|
||||
source: "The current file is available here %{url}"
|
||||
custom_fields:
|
||||
field:
|
||||
_alias: "Property available in liquid templates"
|
||||
hint: "Text displayed in the model form just below the field"
|
||||
content_instance:
|
||||
_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."
|
||||
@ -94,7 +90,12 @@ en:
|
||||
samples: "If enabled, the import process will also copy contents and assets"
|
||||
reset: "If enabled, all the data of your site will be destroyed before importing the new site"
|
||||
content_type:
|
||||
name: "We suggest you to type the plural form of the model. Ex: Projects, Recipes, Posts, Articles, ...etc"
|
||||
slug: "It will be used as the name of the collection in the liquid templates. Ex: {{ contents.my_projects }}"
|
||||
item_template: "You can customize the text displayed for each item in the list. Simply use Liquid. Ex: {{ content.name }})"
|
||||
api_enabled: "It is used to let people from outside to create new instances (example: messages in a contact form)"
|
||||
api_accounts: "A notification email will be sent to each of the accounts listed above when a new instance is created"
|
||||
"custom_fields/field":
|
||||
name: "Name of the property for liquid templates. Ex: {{ your_object.<name_of_your_field> }}"
|
||||
hint: "Text displayed in the model form just below the field"
|
||||
|
||||
|
7
doc/TODO
7
doc/TODO
@ -41,9 +41,12 @@ x edit my site
|
||||
x position
|
||||
x open the nested form
|
||||
x remove an entry
|
||||
- look n feel
|
||||
x look n feel
|
||||
x display errors
|
||||
x slugify
|
||||
- other content type options
|
||||
- show / hide options of a field based on its type
|
||||
- display errors
|
||||
- refactor highlighted_field (field id instead of name)
|
||||
- change in main menu
|
||||
- manage contents
|
||||
- list
|
||||
|
@ -305,7 +305,7 @@ module Locomotive
|
||||
content.send(field.safe_alias.to_sym)
|
||||
end)
|
||||
|
||||
hash[field._alias] = value unless value.blank?
|
||||
hash[field._alias] = value if value.present? || value == false # False values should be preserved in the export
|
||||
end
|
||||
|
||||
data << { content.highlighted_field_value => hash }
|
||||
|
@ -9,13 +9,6 @@ module Locomotive
|
||||
included do
|
||||
include ::Mongoid::Document
|
||||
include ::Mongoid::Timestamps
|
||||
# include ::Mongoid::CustomFields
|
||||
end
|
||||
|
||||
def as_json(options={})
|
||||
attrs = super(options)
|
||||
attrs["id"] = attrs["_id"]
|
||||
attrs
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -2,6 +2,16 @@
|
||||
|
||||
require 'mongoid'
|
||||
|
||||
module Mongoid
|
||||
module Document
|
||||
def as_json(options={})
|
||||
attrs = super(options)
|
||||
attrs["id"] = attrs["_id"]
|
||||
attrs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Limit feature for embedded documents
|
||||
|
||||
module Mongoid #:nodoc:
|
||||
|
@ -9,7 +9,7 @@ gemfile = File.expand_path('../../../../Gemfile', __FILE__)
|
||||
# delayed job version is released?
|
||||
#
|
||||
require 'yaml'
|
||||
YAML::ENGINE.yamler = 'syck'
|
||||
YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE)
|
||||
|
||||
if File.exist?(gemfile)
|
||||
ENV['BUNDLE_GEMFILE'] = gemfile
|
||||
|
@ -25,7 +25,8 @@ describe Locomotive::Export do
|
||||
end
|
||||
|
||||
it 'deals with real booleans' do
|
||||
@project_data.first.values.first['active'].should be_true
|
||||
@project_data.first.values.first['active'].should === true
|
||||
@project_data.last.values.first['active'].should === false
|
||||
end
|
||||
|
||||
it 'stores the list of highlighted values in a has_many relationship' do
|
||||
|
@ -14,7 +14,6 @@ describe Locomotive::ContentInstance do
|
||||
end
|
||||
|
||||
describe '#validation' do
|
||||
|
||||
it 'is valid' do
|
||||
build_content.should be_valid
|
||||
end
|
||||
@ -32,14 +31,37 @@ describe Locomotive::ContentInstance do
|
||||
content.should_not be_valid
|
||||
content.errors[:_slug].should == ["can't be blank"]
|
||||
end
|
||||
|
||||
it 'has an unique permalink' do
|
||||
build_content.save; @content_type = Locomotive::ContentType.find(@content_type._id)
|
||||
content = build_content
|
||||
content.should_not be_valid
|
||||
content.errors[:_slug].should == ["is already taken"]
|
||||
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
|
||||
|
@ -90,6 +90,20 @@ describe Locomotive::ContentType do
|
||||
@content_type.ordered_contents.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
|
||||
@content_type = FactoryGirl.build(:content_type, :order_by => 'created_at')
|
||||
@content_type.content_custom_fields.build :label => 'Active at', :name => 'active_at', :kind => '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) }
|
||||
@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]
|
||||
@content_type.order_direction = 'desc'
|
||||
@content_type.ordered_contents.map(&:active_at).should == [l,e,nil]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'custom fields' do
|
||||
|
Loading…
Reference in New Issue
Block a user