merge in master
This commit is contained in:
commit
53074502b1
|
@ -272,6 +272,7 @@ It takes four parameters:
|
|||
- `partial`: explicitly declare the name of the partial that will be used
|
||||
- `render_options` : options passed through to the form-builder function (e.g. `simple_fields_for`, `semantic_fields_for` or `fields_for`).
|
||||
If it contains a `:locals` option containing a hash, that is handed to the partial.
|
||||
- `wrap_object` : a proc that will allow to wrap your object, especially useful if you are using decorators (e.g. draper). See example lower.
|
||||
|
||||
Optionally you could also leave out the name and supply a block that is captured to give the name (if you want to do something more complicated).
|
||||
|
||||
|
@ -301,6 +302,49 @@ To overrule the default partial name, e.g. because it shared between multiple vi
|
|||
= link_to_add_association 'add something', f, :something, :partial => 'shared/something_fields'
|
||||
````
|
||||
|
||||
#### :wrap_object
|
||||
|
||||
If you are using decorators, the normal instantiation of the associated will not be enough, actually you want to generate the decorated object.
|
||||
|
||||
A simple decorator would look like:
|
||||
|
||||
```
|
||||
class CommentDecorator
|
||||
def initialize(comment)
|
||||
@comment = comment
|
||||
end
|
||||
|
||||
def formatted_created_at
|
||||
@comment.created_at.to_formatted_s(:short)
|
||||
end
|
||||
|
||||
def method_missing(method_sym, *args)
|
||||
if @comment.respond_to?(method_sym)
|
||||
@comment.send(method_sym, *args)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
To use this, write
|
||||
|
||||
```
|
||||
link_to_add_association('add something', @form_obj, :comments, :wrap_object => Proc.new {|comment| CommentDecorator.new(comment) })
|
||||
```
|
||||
|
||||
Note that the `:wrap_object` expects an object that is _callable_, so any `Proc` will do. So you could as well use it to do some fancy extra initialisation (if needed).
|
||||
But note you will have to return the (nested) object you want used.
|
||||
E.g.
|
||||
|
||||
|
||||
```
|
||||
link_to_add_association('add something', @form_obj, :comments,
|
||||
:wrap_object => Proc.new { |comment| comment.name = current_user.name; comment })
|
||||
```
|
||||
|
||||
> A cleaner option would be to call a function that performs this initialisation and returns `self` at the end.
|
||||
|
||||
### link_to_remove_association
|
||||
|
||||
|
@ -325,6 +369,16 @@ On insertion or removal the following events are triggered:
|
|||
* `cocoon:before-remove`: called before removing the nested child
|
||||
* `cocoon:after-remove`: called after removal
|
||||
|
||||
To listen to the events, you to have the following code in your javascript:
|
||||
|
||||
$('#container').bind('cocoon:before-insert', function(e, inserted_item) {
|
||||
// ... do something
|
||||
});
|
||||
|
||||
where `e` is the event and the second parameter is the inserted or removed item. This allows you to change markup, or
|
||||
add effects/animations (see example below).
|
||||
|
||||
|
||||
If in your view you have the following snippet to select an `owner`
|
||||
(we use slim for demonstration purposes)
|
||||
|
||||
|
@ -360,12 +414,38 @@ $(document).ready(function() {
|
|||
function() {
|
||||
/* e.g. recalculate order of child items */
|
||||
});
|
||||
|
||||
// example showing manipulating the inserted/removed item
|
||||
|
||||
$('#tasks').bind('cocoon:before-insert', function(e,task_to_be_added) {
|
||||
task_to_be_added.fadeIn('slow');
|
||||
});
|
||||
|
||||
$('#tasks').bind('cocoon:after-insert', function(e, added_task) {
|
||||
// e.g. set the background of inserted task
|
||||
added_task.css("background","red");
|
||||
});
|
||||
|
||||
$('#tasks').bind('cocoon:before-remove', function(e, task) {
|
||||
// allow some time for the animation to complete
|
||||
$(this).data('remove-timeout', 1000);
|
||||
task.fadeOut('slow');
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
````
|
||||
|
||||
Do note that for the callbacks to work there has to be a surrounding container (div), where you can bind the callbacks to.
|
||||
|
||||
|
||||
When adding animations and effects to make the removal of items more interesting, you will also have to provide a timeout.
|
||||
This is accomplished by the following line:
|
||||
|
||||
$(this).data('remove-timeout', 1000);
|
||||
|
||||
Note that you could also immediately add this to your view (on the `.nested-fields` container).
|
||||
|
||||
### Control the Insertion behaviour
|
||||
|
||||
The default insertion location is at the back of the current container. But we have added two `data`-attributes that are read to determine the insertion-node and -method.
|
||||
|
|
|
@ -7,13 +7,6 @@
|
|||
content.replace(reg_exp, with_str);
|
||||
}
|
||||
|
||||
function trigger_before_removal_callback(node) {
|
||||
node.trigger('cocoon:before-remove');
|
||||
}
|
||||
|
||||
function trigger_after_removal_callback(node) {
|
||||
node.trigger('cocoon:after-remove');
|
||||
}
|
||||
|
||||
$('.add_fields').live('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
@ -56,28 +49,33 @@
|
|||
// allow any of the jquery dom manipulation methods (after, before, append, prepend, etc)
|
||||
// to be called on the node. allows the insertion node to be the parent of the inserted
|
||||
// code and doesn't force it to be a sibling like after/before does. default: 'before'
|
||||
insertionNode[insertionMethod](contentNode);
|
||||
var addedContent = insertionNode[insertionMethod](contentNode);
|
||||
|
||||
insertionNode.trigger('cocoon:after-insert', contentNode);
|
||||
insertionNode.trigger('cocoon:after-insert', [contentNode]);
|
||||
});
|
||||
|
||||
$('.remove_fields.dynamic').live('click', function(e) {
|
||||
|
||||
$('.remove_fields.dynamic, .remove_fields.existing').live('click', function(e) {
|
||||
var $this = $(this);
|
||||
var trigger_node = $this.closest(".nested-fields").parent();
|
||||
trigger_before_removal_callback(trigger_node);
|
||||
var node_to_delete = $this.closest(".nested-fields");
|
||||
var trigger_node = node_to_delete.parent();
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
trigger_node.trigger('cocoon:before-remove', [node_to_delete]);
|
||||
|
||||
|
||||
var timeout = trigger_node.data('remove-timeout') || 0;
|
||||
|
||||
setTimeout(function() {
|
||||
if ($this.hasClass('dynamic')) {
|
||||
$this.closest(".nested-fields").remove();
|
||||
trigger_after_removal_callback(trigger_node);
|
||||
});
|
||||
|
||||
$('.remove_fields.existing').live('click', function(e) {
|
||||
var $this = $(this);
|
||||
var trigger_node = $this.closest(".nested-fields").parent();
|
||||
trigger_before_removal_callback(trigger_node);
|
||||
e.preventDefault();
|
||||
} else {
|
||||
$this.prev("input[type=hidden]").val("1");
|
||||
$this.closest(".nested-fields").hide();
|
||||
trigger_after_removal_callback(trigger_node);
|
||||
}
|
||||
trigger_node.trigger('cocoon:after-remove', [node_to_delete]);
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
|
Loading…
Reference in New Issue