This commit is contained in:
did 2011-03-17 17:41:25 +01:00
parent a7959a8de8
commit a66e745746
10 changed files with 1208 additions and 1098 deletions

View File

@ -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

View File

@ -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

View 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')

View File

@ -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'

View File

@ -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')

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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