fix bug #52
This commit is contained in:
parent
a7959a8de8
commit
a66e745746
17
Gemfile.lock
17
Gemfile.lock
@ -111,7 +111,7 @@ GEM
|
||||
net-ssh (~> 2.0.23)
|
||||
nokogiri (~> 1.4.3.1)
|
||||
ruby-hmac
|
||||
formatador (0.0.16)
|
||||
formatador (0.1.1)
|
||||
formtastic (1.2.3)
|
||||
actionpack (>= 2.3.7)
|
||||
activesupport (>= 2.3.7)
|
||||
@ -136,7 +136,7 @@ GEM
|
||||
yui-compressor (>= 0.9.1)
|
||||
json (1.5.1)
|
||||
json_pure (1.4.6)
|
||||
kgio (2.3.2)
|
||||
kgio (2.3.3)
|
||||
launchy (0.3.7)
|
||||
configuration (>= 0.0.5)
|
||||
rake (>= 0.8.1)
|
||||
@ -169,14 +169,12 @@ GEM
|
||||
will_paginate (~> 3.0.pre)
|
||||
net-ssh (2.0.24)
|
||||
nokogiri (1.4.3.1)
|
||||
pickle (0.4.4)
|
||||
pickle (0.4.6)
|
||||
cucumber (>= 0.8)
|
||||
rake
|
||||
rspec (>= 1.3)
|
||||
yard
|
||||
polyglot (0.3.1)
|
||||
proxies (0.2.1)
|
||||
rack (1.2.1)
|
||||
rack (1.2.2)
|
||||
rack-mount (0.6.13)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (0.5.7)
|
||||
@ -242,14 +240,13 @@ GEM
|
||||
treetop (1.4.9)
|
||||
polyglot (>= 0.3.1)
|
||||
trollop (1.16.2)
|
||||
tzinfo (0.3.24)
|
||||
unicorn (3.4.0)
|
||||
kgio (~> 2.2)
|
||||
tzinfo (0.3.25)
|
||||
unicorn (3.5.0)
|
||||
kgio (~> 2.3)
|
||||
rack
|
||||
warden (0.10.7)
|
||||
rack (>= 1.0.0)
|
||||
will_paginate (3.0.pre2)
|
||||
yard (0.6.4)
|
||||
yui-compressor (0.9.4)
|
||||
|
||||
PLATFORMS
|
||||
|
@ -12,12 +12,9 @@ module Admin
|
||||
|
||||
def update
|
||||
@field = @fields.find(params[:id])
|
||||
@field.updated_at = Time.now # forces mongoid to save the object
|
||||
|
||||
params[:custom_field][:category_items_attributes].delete('-1')
|
||||
|
||||
if @field.update_attributes(params[:custom_field])
|
||||
render :json => @field.attributes
|
||||
render :json => @field.to_json
|
||||
else
|
||||
render :json => { :error => t('flash.admin.custom_fields.update.alert') }
|
||||
end
|
||||
|
17
app/views/admin/custom_fields/_category_tmpl.html.haml
Normal file
17
app/views/admin/custom_fields/_category_tmpl.html.haml
Normal file
@ -0,0 +1,17 @@
|
||||
%script{ :id => 'category-tmpl', :type => 'text/x-mustache-template', :'data-base-input-name' => "custom_field[category_items_attributes]" }
|
||||
%li{ :class => "item {{behaviour_flag}} {{new_record_flag}} {{errors_flag}} {{required_flag}}" }
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
{{#if_existing_record}}
|
||||
%input{ :name => '{{base_name}}[id]', :value => '{{{id}}}', :type => 'hidden', :'data-field' => 'id' }
|
||||
%input{ :name => '{{base_name}}[_destroy]', :value => '0', :type => 'hidden', :'data-field' => '_destroy' }
|
||||
{{/if_existing_record}}
|
||||
|
||||
%input{ :name => '{{base_name}}[position]', :value => '{{{position}}}', :type => 'hidden', :'data-field' => 'position' }
|
||||
%input{ :name => '{{base_name}}[name]', :value => '{{{name}}}', :type => 'text', :'data-field' => 'name' }
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span!= t('admin.buttons.new_item')
|
@ -6,18 +6,23 @@
|
||||
|
||||
- if field.string?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :required => required
|
||||
|
||||
- elsif field.text?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :as => :text, :required => required, :input_html => { :class => field.text_formatting }
|
||||
|
||||
- elsif field.category?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.select field._name.to_sym, field.ordered_category_items.collect { |item| [item.name, item.id] }
|
||||
%button.button.light.edit-categories-link{ :type => 'button', :'data-url' => edit_admin_custom_field_path(parent.class.model_name.underscore, parent.slug, field) }
|
||||
%span!= t('.edit_categories')
|
||||
|
||||
- elsif field.boolean?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'toggle' do
|
||||
= form.check_box field._alias.to_sym
|
||||
|
||||
- elsif field.date?
|
||||
= form.input field._alias.to_sym, :label => field.label, :hint => field.hint, :input_html => { :class => 'date' }
|
||||
|
||||
- elsif field.file?
|
||||
= form.custom_input field._alias.to_sym, :label => field.label, :hint => field.hint, :css => 'file' do
|
||||
= form.file_field field._name.to_sym
|
||||
@ -28,4 +33,6 @@
|
||||
%span
|
||||
/
|
||||
!= t('.delete_file')
|
||||
= form.check_box :"remove_#{field._name}"
|
||||
= form.check_box :"remove_#{field._name}"
|
||||
|
||||
= render '/admin/custom_fields/category_tmpl'
|
@ -5,39 +5,13 @@
|
||||
%p!= t('.help')
|
||||
|
||||
= semantic_form_for @field, :as => :custom_field, :url => admin_custom_field_url(@parent.class.model_name.underscore, @parent.slug, @field) do |f|
|
||||
= f.foldable_inputs :name => t('.collection_label'), :class => 'editable-list off' do
|
||||
- @field.ordered_category_items.each do |item|
|
||||
= f.fields_for :category_items, item, :child_index => item._index do |g|
|
||||
%li{ :class => "item added #{'error' unless item.errors.empty?}"}
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
= f.foldable_inputs :name => t('.collection_label'), :class => 'editable-list off'
|
||||
|
||||
= g.text_field :name
|
||||
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
|
||||
= f.fields_for :category_items, @field.category_items.build, :child_index => '-1' do |g|
|
||||
%li{ :class => 'item template' }
|
||||
%span.handle
|
||||
= image_tag 'admin/form/icons/drag.png'
|
||||
|
||||
= g.hidden_field :position, :class => 'position'
|
||||
|
||||
= g.text_field :name, :class => 'string name'
|
||||
|
||||
|
||||
|
||||
%span.actions
|
||||
= link_to image_tag('admin/form/icons/trash.png'), '#', :class => 'remove', :confirm => t('admin.messages.confirm')
|
||||
%button{ :class => 'button light add', :type => 'button' }
|
||||
%span!= t('admin.buttons.new_item')
|
||||
%script{ :type => 'text/javascript', :name => 'data' }
|
||||
!= "var categories = #{collection_to_js(@field.ordered_category_items, :template => CustomFields::Types::Category::Item.new)};"
|
||||
|
||||
.popup-actions
|
||||
%p
|
||||
%button.button.light{ :type => 'button' }
|
||||
%span!= t('admin.shared.form_actions.update')
|
||||
%button.button.light{ :type => 'submit' }
|
||||
%span= t('admin.shared.form_actions.update')
|
@ -31,6 +31,7 @@ javascripts:
|
||||
- public/javascripts/admin/plugins/tiny_mce/tinymce.js
|
||||
- public/javascripts/admin/plugins/json2.js
|
||||
- public/javascripts/admin/plugins/fancybox.js
|
||||
- public/javascripts/admin/plugins/mustache.js
|
||||
- public/javascripts/admin/custom_fields/category.js
|
||||
asset_collections:
|
||||
- public/javascripts/admin/plugins/fancybox.js
|
||||
|
@ -17,7 +17,7 @@ require 'locomotive/routing'
|
||||
require 'locomotive/regexps'
|
||||
require 'locomotive/render'
|
||||
require 'locomotive/import'
|
||||
#require 'locomotive/delayed_job'
|
||||
require 'locomotive/delayed_job'
|
||||
require 'locomotive/middlewares'
|
||||
require 'locomotive/session_store'
|
||||
|
||||
|
@ -14,5 +14,62 @@ module CustomFields
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
module Category # TODO: patch to apply in the next CustomFields version
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
def category_to_hash
|
||||
{ 'category_items' => self.category_items.collect(&:to_hash) }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Item
|
||||
|
||||
def to_hash(more = {})
|
||||
self.fields.keys.inject({}) do |memo, meth|
|
||||
memo[meth] = self.send(meth.to_sym); memo
|
||||
end.merge({
|
||||
'id' => self._id,
|
||||
'new_record' => self.new_record?,
|
||||
'errors' => self.errors
|
||||
}).merge(more)
|
||||
end
|
||||
|
||||
def to_json
|
||||
self.to_hash.to_json
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Field # TODO: patch to apply in the next CustomFields version
|
||||
|
||||
after_save :invalidate_klass
|
||||
|
||||
def to_hash_with_types(more = {})
|
||||
to_hash_without_types(more).tap do |hash|
|
||||
self.class.field_types.keys.each do |type|
|
||||
if self.respond_to?(:"#{type}_to_hash")
|
||||
hash.merge!(self.send(:"#{type}_to_hash"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :to_hash, :types
|
||||
|
||||
protected
|
||||
|
||||
def invalidate_klass
|
||||
target_name = self.association_name.to_s.gsub('_custom_fields', '')
|
||||
self._parent.send(:"invalidate_#{target_name}_klass")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,101 +1,160 @@
|
||||
// edit category collection
|
||||
$(document).ready(function() {
|
||||
$('button.edit-categories-link').click(function() {
|
||||
var link = $(this);
|
||||
$.fancybox({
|
||||
titleShow: false,
|
||||
href: link.attr('data-url'),
|
||||
padding: 0,
|
||||
onComplete: function() { SetupCustomFieldCategoryEditor(link.prev()); },
|
||||
onCleanup: function() { }
|
||||
})
|
||||
});
|
||||
$('button.edit-categories-link').click(function() {
|
||||
var link = $(this);
|
||||
$.fancybox({
|
||||
titleShow: false,
|
||||
href: link.attr('data-url'),
|
||||
padding: 0,
|
||||
onComplete: function() { SetupCustomFieldCategoryEditor(link.prev()); },
|
||||
onCleanup: function() { }
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
var SetupCustomFieldCategoryEditor = function(target) {
|
||||
|
||||
var refreshPosition = function() {
|
||||
jQuery.each($('#edit-custom-field-category .editable-list li.added input.position'), function(index) {
|
||||
$(this).val(index);
|
||||
});
|
||||
};
|
||||
|
||||
$('#edit-custom-field-category .editable-list li.template button').click(function() {
|
||||
var lastRow = $(this).parents('li.template');
|
||||
|
||||
if (lastRow.find('input.name').val() == '') return ;
|
||||
|
||||
var newRow = lastRow.clone(true).removeClass('template').addClass('added new').insertBefore(lastRow);
|
||||
|
||||
var dateFragment = '[' + new Date().getTime() + ']';
|
||||
newRow.find('input, select').each(function(index) {
|
||||
$(this).attr('name', $(this).attr('name').replace('[-1]', dateFragment));
|
||||
});
|
||||
|
||||
// then reset the form
|
||||
lastRow.find('input').val('');
|
||||
|
||||
// warn the sortable widget about the new row
|
||||
$("#edit-custom-field-category .editable-list ol").sortable('refresh');
|
||||
refreshPosition();
|
||||
|
||||
// resize popup
|
||||
$.fancybox.resize();
|
||||
});
|
||||
|
||||
$('#edit-custom-field-category .editable-list li a.remove').click(function(e) {
|
||||
if (confirm($(this).attr('data-confirm'))) {
|
||||
var parent = $(this).parents('li');
|
||||
if (parent.hasClass('new'))
|
||||
parent.remove();
|
||||
else {
|
||||
var field = parent.find('input.position')
|
||||
field.attr('name', field.attr('name').replace('[position]', '[_destroy]'));
|
||||
parent.hide().removeClass('added');
|
||||
}
|
||||
refreshPosition();
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$("#edit-custom-field-category .editable-list ol").sortable({
|
||||
handle: 'span.handle',
|
||||
items: 'li:not(.template)',
|
||||
axis: 'y',
|
||||
update: refreshPosition
|
||||
});
|
||||
|
||||
/* ___ submit ___ */
|
||||
|
||||
var updateSelectOptions = function(list) {
|
||||
var options = '';
|
||||
var selectedValue = target.val();
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
options += '<option value="' + list[i]._id + '" >' + list[i].name + '</option>';
|
||||
}
|
||||
target.html(options);
|
||||
target.val(selectedValue);
|
||||
};
|
||||
|
||||
$('#edit-custom-field-category .popup-actions button').click(function(e) {
|
||||
var form = $('#edit-custom-field-category form');
|
||||
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
url: form.attr('action'),
|
||||
success: function(data) {
|
||||
if (data.error == null) {
|
||||
list = data.category_items.sort(function(a, b) { return (a.position - b.position); });
|
||||
updateSelectOptions(list);
|
||||
$.fancybox.close();
|
||||
} else
|
||||
$.growl("error", data.error);
|
||||
}
|
||||
});
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
var wrapper = $('#edit-custom-field-category');
|
||||
var form = wrapper.find('form.formtastic');
|
||||
var submitButton = wrapper.find('.popup-actions button');
|
||||
var list = wrapper.find('ol');
|
||||
var template = $('#category-tmpl').html();
|
||||
var baseInputName = $('#category-tmpl').attr('data-base-input-name');
|
||||
var data = categories;
|
||||
var index = 0;
|
||||
|
||||
var refreshPosition = function() {
|
||||
$.each(list.find('li.added:visible input[data-field=position]'), function(index) { $(this).val(index); });
|
||||
}
|
||||
|
||||
var updateTargetCallback = function(data) {
|
||||
if (data.error == null) {
|
||||
list = data.category_items.sort(function(a, b) { return (a.position - b.position); });
|
||||
|
||||
var options = '';
|
||||
var selectedValue = target.val();
|
||||
for (var i = 0; i < list.length; i++)
|
||||
options += '<option value="' + list[i].id + '" >' + list[i].name + '</option>';
|
||||
|
||||
target.html(options);
|
||||
target.val(selectedValue);
|
||||
|
||||
$.fancybox.close();
|
||||
} else
|
||||
$.growl("error", data.error);
|
||||
}
|
||||
|
||||
var updateTarget = function(event) {
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
dataType: 'json',
|
||||
data: form.serialize(),
|
||||
url: form.attr('action'),
|
||||
success: updateTargetCallback
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
var registerTemplateEvents = function(domField) {
|
||||
var nameDom = domField.find('input[data-field=name]');
|
||||
|
||||
// bind the "Add field" button
|
||||
domField.find('button').bind('click', function(e) {
|
||||
var newItem = $.extend({}, data.template);
|
||||
newItem.name = nameDom.val().trim();
|
||||
|
||||
if (newItem.name == '') return false;
|
||||
|
||||
addItem(newItem, { refreshPosition: true });
|
||||
|
||||
// reset template values
|
||||
nameDom.val('').focus();
|
||||
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
});
|
||||
|
||||
nameDom.keypress(function(e) {
|
||||
if (e.which == 13) {
|
||||
domField.find('button').trigger('click');
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var registerItemEvents = function(category, domField) {
|
||||
// remove
|
||||
domField.find('a.remove').click(function(e) {
|
||||
if (confirm($(this).attr('data-confirm'))) {
|
||||
if (category.new_record)
|
||||
domField.remove();
|
||||
else
|
||||
domField.hide().find('input[data-field=_destroy]').val(1);
|
||||
|
||||
refreshPosition();
|
||||
|
||||
$.fancybox.resize();
|
||||
}
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
var addItem = function(category, options) {
|
||||
options = $.extend({
|
||||
'is_template': false,
|
||||
'refreshPosition': false
|
||||
}, options);
|
||||
|
||||
category = $.extend({
|
||||
behaviour_flag: function() { return options.is_template ? 'template' : 'added' },
|
||||
new_record_flag: function() { return this.new_record == true && options.is_template == false ? 'new' : '' },
|
||||
errors_flag: function() { return this.errors && this.errors.length > 0 ? 'error' : '' },
|
||||
base_name: function() { return options.is_template ? '' : baseInputName + "[" + index + "]"; },
|
||||
base_dom_id: function() { return options.is_template ? 'category_template' : 'category_' + index; },
|
||||
if_existing_record: function() { return this.new_record == false }
|
||||
}, category);
|
||||
|
||||
var html = Mustache.to_html(template, category);
|
||||
|
||||
if (options.is_template) {
|
||||
domField = list.append(html).find('.template');
|
||||
|
||||
registerTemplateEvents(domField);
|
||||
}
|
||||
else {
|
||||
domField = list.find('> .template').before(html).prev('li');
|
||||
|
||||
registerItemEvents(category, domField);
|
||||
|
||||
list.sortable('refresh');
|
||||
|
||||
if (options.refreshPosition) refreshPosition();
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
$.fancybox.resize();
|
||||
}
|
||||
|
||||
/* ___ SETUP ___ */
|
||||
var setup = function() {
|
||||
// sortable list
|
||||
list.sortable({
|
||||
handle: 'span.handle',
|
||||
items: 'li:not(.template)',
|
||||
axis: 'y',
|
||||
update: refreshPosition
|
||||
});
|
||||
|
||||
// add the template field used to insert the new ones
|
||||
addItem(data.template, { is_template: true });
|
||||
|
||||
// add the existing fields (if present)
|
||||
for (var i = 0; i < data.collection.length; i++)
|
||||
addItem(data.collection[i]);
|
||||
|
||||
submitButton.click(updateTarget);
|
||||
}
|
||||
|
||||
setup(); // <- let's the show begin
|
||||
};
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user