make the edition of content types more robust (ex: better errors handler)
This commit is contained in:
parent
09d6060633
commit
b8b8cef089
BIN
app/assets/images/locomotive/list/icons/move.png
Normal file
BIN
app/assets/images/locomotive/list/icons/move.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 B |
BIN
app/assets/images/locomotive/list/icons/move_off.png
Normal file
BIN
app/assets/images/locomotive/list/icons/move_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 359 B |
@ -14,7 +14,7 @@ class Locomotive.Models.ContentType extends Backbone.Model
|
|||||||
toJSON: ->
|
toJSON: ->
|
||||||
_.tap super, (hash) =>
|
_.tap super, (hash) =>
|
||||||
delete hash.entries_custom_fields
|
delete hash.entries_custom_fields
|
||||||
hash.entries_custom_fields_attributes = @get('entries_custom_fields').toJSONForSave() if @get('entries_custom_fields')
|
hash.entries_custom_fields_attributes = @get('entries_custom_fields').toJSONForSave() if @get('entries_custom_fields')? && @get('entries_custom_fields').length > 0
|
||||||
|
|
||||||
class Locomotive.Models.ContentTypesCollection extends Backbone.Collection
|
class Locomotive.Models.ContentTypesCollection extends Backbone.Collection
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@ class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.For
|
|||||||
initialize: ->
|
initialize: ->
|
||||||
@model = new Locomotive.Models.ContentType(@options.content_type)
|
@model = new Locomotive.Models.ContentType(@options.content_type)
|
||||||
|
|
||||||
window.foo = @model
|
|
||||||
|
|
||||||
Backbone.ModelBinding.bind @
|
Backbone.ModelBinding.bind @
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
@ -64,12 +62,20 @@ class Locomotive.Views.ContentTypes.FormView extends Locomotive.Views.Shared.For
|
|||||||
target.show()
|
target.show()
|
||||||
|
|
||||||
show_error: (attribute, message, html) ->
|
show_error: (attribute, message, html) ->
|
||||||
if attribute == 'entries_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])
|
|
||||||
else
|
|
||||||
super
|
super
|
||||||
|
else
|
||||||
|
return if _.isEmpty(message)
|
||||||
|
|
||||||
|
_.each _.keys(message), (key) =>
|
||||||
|
_messages = message[key]
|
||||||
|
|
||||||
|
if key == 'base'
|
||||||
|
html = $("<div class=\"inline-errors\"><p>#{_messages[0]}</p></div>")
|
||||||
|
@$('#custom_fields_input .list').after(html)
|
||||||
|
else
|
||||||
|
view = @custom_fields_view.find_entry_view(key)
|
||||||
|
view.show_error(_messages[0]) if view?
|
||||||
|
|
||||||
remove: ->
|
remove: ->
|
||||||
@custom_fields_view.remove()
|
@custom_fields_view.remove()
|
||||||
|
@ -28,6 +28,8 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
|||||||
return @
|
return @
|
||||||
|
|
||||||
enable_behaviours: ->
|
enable_behaviours: ->
|
||||||
|
required_input = @$('.required-input input[type=checkbox]')
|
||||||
|
required_input.checkToggle(on_label: required_input.attr('data-on-label'), off_label: required_input.attr('data-off-label'))
|
||||||
@$('li.input.toggle input[type=checkbox]').checkToggle()
|
@$('li.input.toggle input[type=checkbox]').checkToggle()
|
||||||
@render_select_options_view()
|
@render_select_options_view()
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
|||||||
@$('#content_type_contents_custom_field_select_options_input').append(@select_options_view.render().el)
|
@$('#content_type_contents_custom_field_select_options_input').append(@select_options_view.render().el)
|
||||||
|
|
||||||
make_fields_editable: ->
|
make_fields_editable: ->
|
||||||
@$('span.label-input input[type=text], span.type-input select').editableField()
|
@$('.label-input input[type=text], .type-input select').editableField()
|
||||||
|
|
||||||
toggle: (event) ->
|
toggle: (event) ->
|
||||||
event.stopPropagation() & event.preventDefault()
|
event.stopPropagation() & event.preventDefault()
|
||||||
@ -60,13 +62,13 @@ class Locomotive.Views.ContentTypes.CustomFieldEntryView extends Backbone.View
|
|||||||
form.slideUp()
|
form.slideUp()
|
||||||
|
|
||||||
show_error: (message) ->
|
show_error: (message) ->
|
||||||
html = $("<span class=\"inline-errors\">#{message}</div>")
|
html = $("<span class=\"inline-errors\">#{message}</span>")
|
||||||
@$('span.required-input').after(html)
|
@$('.required-input').after(html)
|
||||||
|
|
||||||
remove: (event) ->
|
remove: (event) ->
|
||||||
event.stopPropagation() & event.preventDefault()
|
event.stopPropagation() & event.preventDefault()
|
||||||
|
|
||||||
if confirm($(event.target).attr('data-confirm'))
|
if confirm($(event.target).attr('data-confirm'))
|
||||||
@$('span.label-input input[type=text], span.type-input select').editableField('destroy')
|
@$('.label-input input[type=text], .type-input select').editableField('destroy')
|
||||||
super()
|
super()
|
||||||
@options.parent_view.remove_entry(@model, @)
|
@options.parent_view.remove_entry(@model, @)
|
@ -26,7 +26,7 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
|
|||||||
|
|
||||||
make_list_sortable: ->
|
make_list_sortable: ->
|
||||||
@sortable_list = @$('> ul').sortable
|
@sortable_list = @$('> ul').sortable
|
||||||
handle: 'span.handle'
|
handle: '.handle'
|
||||||
items: 'li.custom-field'
|
items: 'li.custom-field'
|
||||||
axis: 'y'
|
axis: 'y'
|
||||||
update: @refresh_position_entries
|
update: @refresh_position_entries
|
||||||
@ -35,6 +35,13 @@ class Locomotive.Views.ContentTypes.CustomFieldsView extends Backbone.View
|
|||||||
_.each @_entry_views, (view) ->
|
_.each @_entry_views, (view) ->
|
||||||
view.model.set position: $(view.el).index()
|
view.model.set position: $(view.el).index()
|
||||||
|
|
||||||
|
find_entry_view: (key) ->
|
||||||
|
_.find @_entry_views, (view) ->
|
||||||
|
if key.length > 3
|
||||||
|
view.model.id == key
|
||||||
|
else
|
||||||
|
view.model.get('position') == parseInt(key)
|
||||||
|
|
||||||
add_entry: (event) ->
|
add_entry: (event) ->
|
||||||
event.stopPropagation() & event.preventDefault()
|
event.stopPropagation() & event.preventDefault()
|
||||||
|
|
||||||
|
@ -75,11 +75,11 @@ class Locomotive.Views.Shared.FormView extends Backbone.View
|
|||||||
|
|
||||||
show_errors: (errors) ->
|
show_errors: (errors) ->
|
||||||
for attribute, message of errors
|
for attribute, message of errors
|
||||||
if _.isArray(message[0])
|
if _.isString(message[0])
|
||||||
@show_error attribute, message
|
|
||||||
else
|
|
||||||
html = $("<div class=\"inline-errors\"><p>#{message[0]}</p></div>")
|
html = $("<div class=\"inline-errors\"><p>#{message[0]}</p></div>")
|
||||||
@show_error attribute, message[0], html
|
@show_error attribute, message[0], html
|
||||||
|
else
|
||||||
|
@show_error attribute, message
|
||||||
|
|
||||||
show_error: (attribute, message, html) ->
|
show_error: (attribute, message, html) ->
|
||||||
input = @$("##{@model.paramRoot}_#{attribute}")
|
input = @$("##{@model.paramRoot}_#{attribute}")
|
||||||
|
@ -12,6 +12,16 @@ form.formtastic {
|
|||||||
|
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
|
|
||||||
|
span.inline-errors {
|
||||||
|
margin-left: 10px;
|
||||||
|
padding: 2px 3px;
|
||||||
|
|
||||||
|
background: #FFE5E5;
|
||||||
|
|
||||||
|
color: #CE2525;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
legend {
|
legend {
|
||||||
display: block;
|
display: block;
|
||||||
width: 918px;
|
width: 918px;
|
||||||
@ -101,16 +111,6 @@ form.formtastic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span.inline-errors {
|
|
||||||
margin-left: 10px;
|
|
||||||
padding: 2px 3px;
|
|
||||||
|
|
||||||
background: #FFE5E5;
|
|
||||||
|
|
||||||
color: #CE2525;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.actions {
|
span.actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@ -149,9 +149,9 @@ form.formtastic {
|
|||||||
|
|
||||||
&.drag {
|
&.drag {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
background: transparent image-url("locomotive/list/icons/toggle_off.png") repeat 0 0;
|
background: transparent image-url("locomotive/list/icons/move_off.png") repeat 0 0;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-image: image-url("locomotive/list/icons/toggle.png");
|
background-image: image-url("locomotive/list/icons/move.png");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -592,23 +592,34 @@ form.formtastic {
|
|||||||
|
|
||||||
li.custom-field {
|
li.custom-field {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
clear: both;
|
||||||
|
|
||||||
|
& > .col {
|
||||||
|
float: left;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.editable {
|
.editable {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
|
|
||||||
|
width: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.handle {
|
.handle {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 3px;
|
top: 4px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
margin-right: 2px;
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.label-input {
|
.label-input {
|
||||||
|
margin-right: 2px;
|
||||||
|
|
||||||
input[type=text] {
|
input[type=text] {
|
||||||
float: none;
|
float: none;
|
||||||
display: inline;
|
display: inline-block;
|
||||||
|
|
||||||
@include default-input-style;
|
@include default-input-style;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
@ -621,26 +632,31 @@ form.formtastic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span.type-input {
|
.type-input {
|
||||||
display: inline-block;
|
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
|
||||||
.editable {
|
.editable {
|
||||||
// font-style: italic;
|
|
||||||
color: #585A69;
|
color: #585A69;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
width: 150px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span.required-input {
|
.required-input {
|
||||||
margin-left: 10px;
|
|
||||||
|
|
||||||
label {
|
label {
|
||||||
float: none;
|
float: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggleSwitch {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: 0px;
|
||||||
|
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // li.custom-field
|
} // li.custom-field
|
||||||
@ -661,6 +677,7 @@ form.formtastic {
|
|||||||
} // > li
|
} // > li
|
||||||
|
|
||||||
&.nested {
|
&.nested {
|
||||||
|
clear: both;
|
||||||
width: 858px;
|
width: 858px;
|
||||||
border: none;
|
border: none;
|
||||||
@include border-radius(0);
|
@include border-radius(0);
|
||||||
|
@ -37,7 +37,7 @@ module Locomotive
|
|||||||
## validations ##
|
## validations ##
|
||||||
validates_presence_of :site, :name, :slug
|
validates_presence_of :site, :name, :slug
|
||||||
validates_uniqueness_of :slug, :scope => :site_id
|
validates_uniqueness_of :slug, :scope => :site_id
|
||||||
validates_size_of :entries_custom_fields, :minimum => 1, :message => :array_too_short
|
validates_size_of :entries_custom_fields, :minimum => 1, :message => :too_few_custom_fields
|
||||||
|
|
||||||
## behaviours ##
|
## behaviours ##
|
||||||
custom_fields_for :entries
|
custom_fields_for :entries
|
||||||
@ -103,12 +103,15 @@ module Locomotive
|
|||||||
def bubble_fields_errors_up
|
def bubble_fields_errors_up
|
||||||
return if self.errors[:entries_custom_fields].empty?
|
return if self.errors[:entries_custom_fields].empty?
|
||||||
|
|
||||||
self.errors.set(:entries_custom_fields, [])
|
hash = { :base => self.errors[:entries_custom_fields] }
|
||||||
|
|
||||||
self.entries_custom_fields.each do |field|
|
self.entries_custom_fields.each do |field|
|
||||||
next if field.valid?
|
next if field.valid?
|
||||||
self.errors.add(:entries_custom_fields, field.errors.to_a)
|
key = field.persisted? ? field._id.to_s : field.position.to_i
|
||||||
|
hash[key] = field.errors.to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self.errors.set(:entries_custom_fields, hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -20,19 +20,17 @@
|
|||||||
|
|
||||||
= f.semantic_fields_for :contents_custom_field, CustomFields::Field.new do |g|
|
= f.semantic_fields_for :contents_custom_field, CustomFields::Field.new do |g|
|
||||||
|
|
||||||
%span.handle
|
.handle.col
|
||||||
= image_tag 'locomotive/form/icons/drag.png'
|
= image_tag 'locomotive/form/icons/drag.png'
|
||||||
|
|
||||||
%span.label-input
|
.label-input.col
|
||||||
= g.text_field :label, :class => 'label'
|
= g.text_field :label, :class => 'label'
|
||||||
|
|
||||||
%span.type-input
|
.type-input.col
|
||||||
= g.select :type, options_for_custom_field_type, {}, { :class => 'type' }
|
= g.select :type, options_for_custom_field_type, {}, { :class => 'type' }
|
||||||
|
|
||||||
%span.required-input
|
.required-input.col
|
||||||
= g.check_box :required, :class => 'required'
|
= g.check_box :required, :class => 'required', :'data-on-label' => t('.required'), :'data-off-label' => t('.optional')
|
||||||
|
|
||||||
= g.label :required, t('.is_required')
|
|
||||||
|
|
||||||
%ol.nested{ :style => 'display: none' }
|
%ol.nested{ :style => 'display: none' }
|
||||||
|
|
||||||
@ -50,6 +48,8 @@
|
|||||||
= link_to 'toggle', '#', :class => 'toggle'
|
= link_to 'toggle', '#', :class => 'toggle'
|
||||||
= link_to 'x', '#', :class => 'remove', :confirm => t('locomotive.messages.confirm')
|
= link_to 'x', '#', :class => 'remove', :confirm => t('locomotive.messages.confirm')
|
||||||
|
|
||||||
|
.clear
|
||||||
|
|
||||||
|
|
||||||
%script{ :type => 'text/html', :id => 'select_options_list' }
|
%script{ :type => 'text/html', :id => 'select_options_list' }
|
||||||
|
|
||||||
|
@ -5,10 +5,3 @@
|
|||||||
- if current_site.locales.size > 1
|
- if current_site.locales.size > 1
|
||||||
.action
|
.action
|
||||||
= render 'locomotive/shared/locale_picker_link'
|
= render 'locomotive/shared/locale_picker_link'
|
||||||
/ = link_to '#', :id => 'content-locale-picker-link', :class => 'button' do
|
|
||||||
/ %span.hand
|
|
||||||
/
|
|
||||||
/
|
|
||||||
/ = image_tag "locomotive/icons/flags/#{current_content_locale}.png", :class => 'flag'
|
|
||||||
/
|
|
||||||
/ %span.text= current_content_locale
|
|
@ -71,7 +71,8 @@ en:
|
|||||||
has_many:
|
has_many:
|
||||||
empty: Empty
|
empty: Empty
|
||||||
form:
|
form:
|
||||||
is_required: is required
|
required: Required
|
||||||
|
optional: Optional
|
||||||
default_label: Field name
|
default_label: Field name
|
||||||
select_options:
|
select_options:
|
||||||
ask_name: "Type the label of the option"
|
ask_name: "Type the label of the option"
|
||||||
|
@ -16,6 +16,7 @@ en:
|
|||||||
page:
|
page:
|
||||||
liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')"
|
liquid_syntax: "Liquid Syntax error ('%{error}' on '%{fullpath}')"
|
||||||
liquid_extend: "The page '%{fullpath}' extends a template which does not exist"
|
liquid_extend: "The page '%{fullpath}' extends a template which does not exist"
|
||||||
|
too_few_custom_fields: "At least, one custom field is required"
|
||||||
|
|
||||||
attributes:
|
attributes:
|
||||||
defaults:
|
defaults:
|
||||||
|
6
doc/TODO
6
doc/TODO
@ -63,9 +63,9 @@ x edit my site
|
|||||||
x destroy
|
x destroy
|
||||||
x public_form (previously api something)
|
x public_form (previously api something)
|
||||||
x bug text formatting
|
x bug text formatting
|
||||||
|
x custom_fields: use the appropriate icon to drag select options
|
||||||
- use list_or_group_entries instead of ordered_entries
|
- use list_or_group_entries instead of ordered_entries
|
||||||
- bug ui with contents popup
|
- bug ui with contents popup
|
||||||
- custom_fields: use the appropriate icon to drag select options
|
|
||||||
- i18n
|
- i18n
|
||||||
x add locales a site responds to
|
x add locales a site responds to
|
||||||
x locale switcher
|
x locale switcher
|
||||||
@ -84,10 +84,8 @@ x edit my site
|
|||||||
- i18n
|
- i18n
|
||||||
- insert image
|
- insert image
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- bugs:
|
- bugs:
|
||||||
- unable to toggle the "required" check_boxes for content types
|
x unable to toggle the "required" check_boxes for content types
|
||||||
|
|
||||||
- disallow to click twice on the submit form button (spinner ?)
|
- disallow to click twice on the submit form button (spinner ?)
|
||||||
- message to notify people if their browser is too old
|
- message to notify people if their browser is too old
|
||||||
|
@ -388,7 +388,7 @@ Backbone.ModelBinding = (function(Backbone, _, $){
|
|||||||
array = _.without(array, value);
|
array = _.without(array, value);
|
||||||
data[attr_name] = array;
|
data[attr_name] = array;
|
||||||
} else
|
} else
|
||||||
data[attr_name] = value;
|
data[attr_name] = checked;
|
||||||
model.set(data);
|
model.set(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user