I"ï (function() { var init_sortable, recompute_positions; $(function() { $(document).on('click', 'a.button.has_many_remove', function(e) { var parent, to_remove; e.preventDefault(); parent = $(this).closest('.has_many_container'); to_remove = $(this).closest('fieldset'); recompute_positions(parent); parent.trigger('has_many_remove:before', [to_remove, parent]); to_remove.remove(); return parent.trigger('has_many_remove:after', [to_remove, parent]); }); $(document).on('click', 'a.button.has_many_add', function(e) { var before_add, fieldset, html, index, parent, regex; e.preventDefault(); parent = $(this).closest('.has_many_container'); parent.trigger(before_add = $.Event('has_many_add:before'), [parent]); if (!before_add.isDefaultPrevented()) { index = parent.data('has_many_index') || parent.children('fieldset').length - 1; parent.data({ has_many_index: ++index }); regex = new RegExp($(this).data('placeholder'), 'g'); html = $(this).data('html').replace(regex, index); fieldset = $(html).insertBefore(this); recompute_positions(parent); return parent.trigger('has_many_add:after', [fieldset, parent]); } }); $(document).on('change', '.has_many_container[data-sortable] :input[name$="[_destroy]"]', function() { return recompute_positions($(this).closest('.has_many')); }); init_sortable(); return $(document).on('has_many_add:after', '.has_many_container', init_sortable); }); init_sortable = function() { var elems; elems = $('.has_many_container[data-sortable]:not(.ui-sortable)'); elems.sortable({ items: '> fieldset', handle: '> ol > .handle', stop: recompute_positions }); return elems.each(recompute_positions); }; recompute_positions = function(parent) { var input_name, position; parent = parent instanceof jQuery ? parent : $(this); input_name = parent.data('sortable'); position = parseInt(parent.data('sortable-start') || 0, 10); return parent.children('fieldset').each(function() { var destroy_input, sortable_input; destroy_input = $(this).find("> ol > .input > :input[name$='[_destroy]']"); sortable_input = $(this).find("> ol > .input > :input[name$='[" + input_name + "]']"); if (sortable_input.length) { return sortable_input.val(destroy_input.is(':checked') ? '' : position++); } }); }; }).call(this); :ET