Skip to content

Instantly share code, notes, and snippets.

@juanmf
Last active August 29, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juanmf/10483041 to your computer and use it in GitHub Desktop.
Save juanmf/10483041 to your computer and use it in GitHub Desktop.
/**
* Recursive Prototype Clonner:
* it relies on the following data structure:
* <someAncestor data-allow-add="true"> ...
* <button class="" data-add="add"
* data-add-prototype-node="JQ selector relative to $button.closest('[data-allow-add]'). Will be parameter of $obj.find($selector)"
* data-add-prototype-name="<?php echo $prototypeName; ?> optional, defauts to __name__"
* data-add-append-node="%data-add-prototype-node% | JQ selector relative to $button.closest('[data-allow-add]').
* Will be parameter of $obj.find($selector)"
* data-add-wrapper="html to wrap the cloned item before appending e.g. <li>__PROTOTYPE-CONTENT__</li>"
* > ...
* </someAncestor>
* e.g.
* <button class="" data-add="add"
data-add-prototype-node="ul.preciosTierra"
data-add-append-node="ul.preciosTierra"
data-add-wrapper="<?php echo htmlentities(
'<li data-allow-add="true">'
. $botonesDepto
. '__PROTOTYPE-CONTENT__'
. '</li>'); ?>"
>Crear Nueva Area</button>
*/
/** from http://stackoverflow.com/questions/322912/jquery-to-find-all-previous-elements-that-match-an-expression */
// this is a small helper extension i stole from
// http://www.texotela.co.uk/code/jquery/reverse/
// it merely reverses the order of a jQuery set.
$.fn.reverse = function() {
return this.pushStack(this.get().reverse(), arguments);
};
// create two new functions: prevALL and nextALL. they're very similar, hence this style.
$.each( ['prev', 'next'], function(unusedIndex, name) {
$.fn[ name + 'ALL' ] = function(matchExpr) {
// get all the elements in the body, including the body.
var $all = $('body').find('*').andSelf();
// slice the $all object according to which way we're looking
$all = (name == 'prev')
? $all.slice(0, $all.index(this)).reverse()
: $all.slice($all.index(this) + 1)
;
// filter the matches if specified
if (matchExpr) $all = $all.filter(matchExpr);
return $all;
};
});
/***End from */
docdigital = (typeof docdigital === "undefined") ? {} : docdigital;
$.extend(true, docdigital, {
constants: {
mediator: {
messages: {
clonePrototype_prototypeAdded: 'clonePrototype_prototypeAdded'
}
}
}
});
$.extend(true, docdigital, {
ColonePrototype: function () {
this.bindDelete = function () {
$('[data-allow-add] button[data-delete]').attr('onclick','').unbind('click');
$('[data-allow-add] button[data-delete]')
.click(
function(event) {
var $button = $(event.target);
var $container = $button.closest('[data-allow-add]');
var $prototypeNode = $container.find(($button.attr('data-add-prototype-node')));
var $appendTarget = $button.attr('data-add-append-node') === '%data-add-prototype-node%'
? $prototypeNode
: $container.find($button.attr('data-add-append-node'));
$appendTarget.each(function() {
var $toDelete = $(this).children().last();
$toDelete.remove();
});
// child Counter update
parseInt($button.attr('data-count')) > 0
&& $button.attr(
'data-count',
parseInt($button.attr('data-count')) - 1
);
return false;
}
);
};
this.bindAdd = function () {
$('[data-allow-add] button[data-add]').attr('onclick','').unbind('click');
$('[data-allow-add] button[data-add]')
.click(
function(event) {
var $button = $(event.target);
var $container = $button.closest('[data-allow-add]');
var $prototypeNode = $container.find(($button.attr('data-add-prototype-node')));
var $prototypeName = $button.attr('data-add-prototype-name') || '__name__';
var $appendTarget = $button.attr('data-add-append-node') === '%data-add-prototype-node%'
? $prototypeNode
: $container.find($button.attr('data-add-append-node'));
var $wrappingHtml = $button.attr('data-add-wrapper') && $button.attr('data-add-wrapper').length > 0
? $button.attr('data-add-wrapper')
: false;
$button.attr('data-count')
|| $button.attr(
'data-count',
$appendTarget.first().children().length
);
var nameRegex = new RegExp($prototypeName, 'g');
var labelRegex = new RegExp($prototypeName + 'label__', 'g');
$appendTarget.each(function(idx, element) {
var $clone = $prototypeNode.eq(idx).attr('data-prototype');
$clone = $clone.replace(labelRegex, $button.attr('data-count'));
$clone = $clone.replace(nameRegex, $button.attr('data-count'));
if ($wrappingHtml) {
$clone = $wrappingHtml.replace(/__PROTOTYPE-CONTENT__/g, $clone)
}
$clone = $.parseHTML($clone);
$(this).append($clone);
docdigital.mediatorInstance.send(
docdigital.constants.mediator.messages.clonePrototype_prototypeAdded,
$clone
);
});
$button.attr('data-count', parseInt($button.attr('data-count')) + 1);
var c = new docdigital.ColonePrototype();
$('li[data-allow-add] > div').each(c.tabIndxFn);
c.bindAdd();
c.bindDelete();
return false;
}
);
};
}
});
$(document).ready(
function () {
var clonner = new docdigital.ColonePrototype();
clonner.bindAdd();
clonner.bindDelete();
}
);
@dotstormz
Copy link

Can you give an example of this code working with multiple nested collections?

@ahmed91w
Copy link

ahmed91w commented Feb 7, 2015

Hello i have the same problem with multiple nested collections . can anybody help me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment