From 2ba72fd72dfbaa75392af8cc3dcb44040a319ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Sauveton?= Date: Fri, 23 Oct 2015 16:56:31 +0200 Subject: [PATCH] #3854 --- .../sheepit/jquery.sheepItPlugin.min.js | 1575 ++++++++++++++++- 1 file changed, 1574 insertions(+), 1 deletion(-) diff --git a/www/include/common/javascript/jquery/plugins/sheepit/jquery.sheepItPlugin.min.js b/www/include/common/javascript/jquery/plugins/sheepit/jquery.sheepItPlugin.min.js index 95cc5e84341..baa83d30908 100644 --- a/www/include/common/javascript/jquery/plugins/sheepit/jquery.sheepItPlugin.min.js +++ b/www/include/common/javascript/jquery/plugins/sheepit/jquery.sheepItPlugin.min.js @@ -1 +1,1574 @@ -(function(e){jQuery.fn.sheepIt=function(t){function n(){var e;if(typeof t.beforeClone==="function"){t.beforeClone(st,dt)}e=dt.cloneWithAttribut(true);if(typeof t.afterClone==="function"){t.afterClone(st,e)}e.getSource=function(){return st};return e}function r(e){e.preventDefault();g()}function i(e){e.preventDefault();if(at.value!==""){y(at.attr("value"))}}function s(n){n.preventDefault();if(typeof t.beforeRemoveCurrent==="function"){t.beforeRemoveCurrent(st)}if(t.removeCurrentConfirmation){if(confirm(t.removeCurrentConfirmationMsg)){E(e(this).data("removableClone"))}}else{E(e(this).data("removableClone"))}if(typeof t.afterRemoveCurrent==="function"){t.afterRemoveCurrent(st)}}function o(e){e.preventDefault();if(t.removeLastConfirmation){if(confirm(t.removeLastConfirmationMsg)){b()}}else{b()}}function u(e){e.preventDefault();if(t.removeAllConfirmation){if(confirm(t.removeAllConfirmationMsg)){w()}}else{w()}}function a(e,t){var n=e.attr(t);e.attr(t+"template",escape(n));return n}function f(n,r){n.find(gt).each(function(){var i=e(this),s=a(i,"id"),o=a(i,"name"),u=i.attr("id"),f=i.attr("name");if(typeof newNameAttr=="string"){newNameAttr=o.replace(t.indexFormat,r);i.attr("name",newNameAttr)}if(typeof newIdAttr=="string"){newIdAttr=s.replace(t.indexFormat,r);n.find("label[for='"+u+"']").each(function(){e(this).attr("for",newIdAttr)});i.attr("id",newIdAttr)}})}function l(e,t){c(e,t+1)}function c(e,n){e.find(t.labelSelector).html(n);return true}function h(e){return e.find(t.labelSelector).html()}function p(){if(R()){if(D()==1){ht.hideIf();lt.showIf()}else{ht.showIf();lt.showIf()}var e="";if(t.allowRemoveCurrent){e=st.find(t.removeCurrentSelector);if(z()){e.show()}else{e.hide()}}else{e=st.find(t.removeCurrentSelector);e.hide()}}else{lt.hideIf();ht.hideIf()}if(!U()){ot.hideIf();ut.hideIf()}else{ot.showIf();ut.showIf()}if(!z()){lt.hideIf();ht.hideIf()}if(ot.css("display")!="none"||ut.css("display")!="none"||ht.css("display")!="none"||lt.css("display")!="none"){pt.show()}else{pt.hide()}}function d(){if(R()){mt.hide();if(t.continuousIndex){var e=0,n=P();do{v(n,e);e++;n=B(n)}while(n!=false)}}else{mt.show()}}function v(e,n){if(typeof n=="undefined"){n=_()}var r=a(e,"id");if(e.attr("id")){e.attr("id",r+n)}f(e,n);l(e,n);if(e.html().indexOf(t.indexFormat)!=-1){var i=new RegExp(t.indexFormat,"ig");e.html(e.html().replace(i,n))}var s=e.find(t.removeCurrentSelector);t.allowRemoveCurrent?s.show():s.hide();return e}function m(){d();p()}function g(r,i){if(typeof r=="undefined"){r=true}if(typeof i=="undefined"){i=false}if(typeof t.beforeAdd==="function"){t.beforeAdd(st)}var o=false;if(i){if(typeof i=="string"){o=e("#"+i)}else if(typeof i=="object"){o=i}else{return false}o.remove()}else{o=n()}if(U()&&o){o=v(o);var u=o.find(t.removeCurrentSelector).first();u.click(s);u.data("removableClone",o);o.data("formIndex",_());o.data("previousSeparator",false);o.data("nextSeparator",false);o.data("previousForm",false);o.data("nextForm",false);if(R()){var a=H();a.data("nextForm",o);o.data("previousForm",a);if(t.separator){var f=G();f.insertAfter(a);a.data("nextSeparator",f);o.data("previousSeparator",f)}}t.insertNewForms=="after"?o.insertBefore(mt):o.insertAfter(mt);if(t.nestedForms.length>0){var l=0;var c=[];for(l in t.nestedForms){if(typeof t.nestedForms[l].id!="undefined"&&typeof t.nestedForms[l].options!="undefined"){t.nestedForms[l].isNestedForm=true;t.nestedForms[l].parentForm=st;var h=t.nestedForms[l].id.replace(t.indexFormat,o.data("formIndex"));var p=e("#"+h).sheepIt(t.nestedForms[l].options);c.push(p)}}o.data("nestedForms",c)}rt(o);yt.push(o);if(r||t.continuousIndex){m()}if(typeof t.afterAdd==="function"){t.afterAdd(st,o)}return true}else{return false}}function y(e,t){if(typeof e!="undefined"){e=parseFloat(e);var n=1;for(n=1;n<=e;n++){g(t)}}}function b(e){if(typeof e=="undefined"){e=true}if(z()){S();if(e){m()}return true}else{return false}}function w(e){if(typeof e=="undefined"){e=true}if(W()){var t=[];for(t in yt){if(yt[t]){S(yt[t])}}if(e){m()}return true}else{return false}}function E(e,t){if(typeof t=="undefined"){t=true}if(z()){S(e);if(t){m()}return true}else{return false}}function S(e){if(typeof e=="undefined"){e=H()}index=e.data("formIndex");if(e.data("previousSeparator")&&e.data("nextSeparator")){e.data("previousSeparator").remove();e.data("previousForm").data("nextSeparator",e.data("nextSeparator"))}else if(e.data("previousSeparator")&&!e.data("nextSeparator")){e.data("previousSeparator").remove();e.data("previousForm").data("nextSeparator",false)}else if(!e.data("previousSeparator")&&e.data("nextSeparator")){e.data("nextSeparator").remove();e.data("nextForm").data("previousSeparator",false)}if(e.data("previousForm")){e.data("previousForm").data("nextForm",e.data("nextForm"))}if(e.data("nextForm")){e.data("nextForm").data("previousForm",e.data("previousForm"))}yt[index]=false;e.remove();return true}function x(){return bt}function T(){if(bt!==false){if(yt.length>1){var e=0;var t=parseFloat(bt+1);for(e=t;e1){var e=0;var t=parseFloat(bt-1);for(e=t;e>=0;e--){if(yt[e]){bt=e;return true}}return false}else{return false}}else{return false}}function C(){bt=false;if(yt.length>0){var e=0;for(;e0){if(yt[yt.length-1]){bt=yt.length-1;return true}else{var e=0;for(e=yt.length-1;e>=0;e--){if(yt[e]){bt=e;return true}}return false}}else{return false}}function L(){if(yt.length>0){return yt.length}else{return 0}}function A(e){if(typeof e!="undefined"){bt=O(e);if(bt!==false){return true}else{return false}}else{return false}}function O(e){var t=0;var n=0;var r=false;for(t=0;t0?true:false}function U(){if(t.maxFormsCount==0){return true}else{return D()t.minFormsCount?true:false}function W(){return t.minFormsCount==0?true:false}function X(t){if(e("#"+t.attr("id")).length>0){return true}else{return false}}function V(n,r){var i="";if(typeof n=="number"){n++;if(n>D()){g()}i=I(n);J(i,r)}else if(typeof n=="string"){i=e("#"+n);J(i,r)}if(typeof t.afterFill==="function"){t.afterFill(st,i,r)}}function J(n,r){var i=0;e.each(r,function(e,r){var s=st.attr("id");var o=n.data("formIndex");var u="#index#";if(typeof t.indexFormat!="undefined"&&t.indexFormat){u=t.indexFormat}if(e.indexOf("#form#")!=-1||e.indexOf(u)!=-1){e=e.replace("#form#",s);e=e.replace(u,o)}else{e=s+"_"+o+"_"+e}var a=n.find(':input[id="'+e+'"]');if(a.length==0){a=n.find(':input[name="'+e+'"]');if(a.length==0){a=n.find(':input[name="'+e+'[]"]')}}if(a.length>0){var f=false;if(typeof r=="object"){f=true}var l=false;if(a.length>1){l=true}if(l){if(f){var c=[];c["fields"]=[];c["values"]=[];i=0;for(i in r){c["fields"].push(a.filter('[value="'+r[i]+'"]'));c["values"].push(r[i])}i=0;for(i in c["fields"]){K(c["fields"][i],c["values"][i])}}else{K(a.filter('[value="'+r+'"]',r))}}else{if(f){i=0;for(i in r){K(a,r[i])}}else{K(a,r)}}}else{if(typeof n.data("nestedForms")!="undefined"){if(n.data("nestedForms").length>0){i=0;for(i in n.data("nestedForms")){if(e==n.data("nestedForms")[i].attr("id")&&typeof r=="object"){n.data("nestedForms")[i].inject(r)}}}}}})}function K(t,n){var r=t.attr("type");if(r=="text"||r=="hidden"||r=="password"){t.attr("value",n);return true}else if(r=="textarea"){t.text(n);return true}else if(r=="checkbox"||r=="radio"){t.attr("checked","checked");return true}else if(r=="select-one"||r=="select-multiple"){t.find("option").each(function(){if(e(this).text()==n||e(this).attr("value")==n){e(this).attr("selected","selected")}});return true}else{return false}}function Q(){if(t.separator!=""){return true}else{return false}}function G(){if(Q()){return e(t.separator)}else{return false}}function Y(n){t=[];t=e.extend(wt,n);it(t)}function Z(){return t}function et(){st.hide();ot=e(t.addSelector);ut=e(t.addNSelector);at=e(t.addNInputSelector);ft=e(t.addNButtonSelector);lt=e(t.removeLastSelector);ct=e(t.removeCurrentSelector);ht=e(t.removeAllSelector);pt=e(t.controlsSelector);if(ot.length==0){t.allowAdd=false}if(ut.length==0){t.allowAddN=false}if(lt.length==0){t.allowRemoveLast=false}if(ht.length==0){t.allowRemoveAll=false}tt(ot,t.allowAdd,r);tt(ut,t.allowAddN,i,ft);tt(lt,t.allowRemoveLast,o);tt(ht,t.allowRemoveAll,u);ot.init();ut.init();lt.init();ht.init();vt=e(t.formTemplateSelector);mt=e(t.noFormsTemplateSelector);dt=vt.cloneWithAttribut(true);vt.remove();var n=0;if(t.pregeneratedForms.length>0){n=0;for(n in t.pregeneratedForms){g(false,t.pregeneratedForms[n])}}if(t.iniFormsCount>D()){n=0;var s=t.iniFormsCount-D();for(n=1;n<=s;n++){g(false)}}if(t.data){st.inject(t.data)}m();st.show()}function tt(t,n,r,i){if(typeof i=="undefined"){i=false}e.extend(t,{hideIf:function(e,r){if(n){t.hide(e,r)}},showIf:function(e,r){if(n){t.show(e,r)}},init:function(){if(n){if(i){i.click(r)}else{t.click(r)}t.show()}else{t.hide()}}})}function nt(n){e.extend(n,{getAddControl:function(){return ot},getAddNControl:function(){return ut},getRemoveLastControl:function(){return lt},getRemoveAllControl:function(){return ht},getOptions:function(){return Z()},getOption:function(e){return t[e]},setOption:function(e,n){if(typeof e!="undefined"&&typeof n!="undefined"){t[e]=n;return t[e]}else{return false}},getForms:function(){return q()},getAllForms:function(){return q()},getForm:function(e){if(typeof e!="undefined"){e++}return I(e)},getLastForm:function(){return I()},getFirstForm:function(){C();return F()},addForm:function(){return g()},addNForms:function(e){return y(e)},getFormsCount:function(){return D()},hasForms:function(){return R()},canAddForm:function(){return U()},canRemoveAllForms:function(){return W()},canRemoveForm:function(){return z()},removeAllForms:function(){return w()},removeLastForm:function(){return b()},removeFirstForm:function(){C();return S(F())},removeForm:function(e){if(typeof e!="undefined"){e++}return S(I(e))},inject:function(t){e.each(t,e.proxy(V,n))}})}function rt(t){e.extend(t,{setLabel:function(e){return c(t,e)},getLabel:function(){return h(t)},inject:function(e){J(t,e)},getNestedForms:function(){return t.data("nestedForms")},getNestedForm:function(e){return t.data("nestedForms")[e]},getPosition:function(){return M(t.data("formIndex"))},getPreviousForm:function(){return j(t)},getNextForm:function(){return B(t)},removeForm:function(){return S(t)}})}function it(e){if(e.maxFormsCount>0){if(e.maxFormsCounte.maxFormsCount){e.iniFormsCount=e.minFormsCount}}else{if(e.iniFormsCount',iniFormsCount:1,maxFormsCount:20,minFormsCount:1,incrementCount:1,noFormsMsg:"No forms to display",indexFormat:"#index#",data:[],pregeneratedForms:[],nestedForms:[],isNestedForm:false,parentForm:{},beforeClone:function(){},afterClone:function(){},beforeAdd:function(){},afterAdd:function(){},afterFill:function(){},afterRemoveCurrent:function(){},beforeRemoveCurrent:function(){},insertNewForms:"after",continuousIndex:true};Y(t);et();return st};jQuery.fn.cloneWithAttribut=function(t){if(jQuery.support.noCloneEvent){return e(this).clone(t)}else{e(this).find("*").each(function(){e(this).data("name",e(this).attr("name"))});var n=e(this).clone(t);n.find("*").each(function(){e(this).attr("name",e(this).data("name"))});return n}}})(jQuery) +/** + * SheepIt! Jquery Plugin + * http://www.mdelrosso.com/sheepit/ + * + * @version 1.1.1 + * + * Created By Mariano Del Rosso (http://www.mdelrosso.com) + * + * Thanks to: + * Hubert Galuszka: Continuous index option and support for tabular forms + * Gabriel Alonso: Bugfixes + * + * @license + * + * SheepIt is free software: you can redistribute it and/or modify + * it under the terms of the MIT license + * + * SheepIt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MIT license for more details. + * + * You should have received a copy of the MIT license + * along with SheepIt. If not, see . + */ + +(function($){ + + jQuery.fn.sheepIt = function (options){ + + + /** + * Clone the form template + */ + function cloneTemplate() + { + var clone; + + // Before clone callBack function + if (typeof options.beforeClone === "function") { + options.beforeClone(source, template); + } + clone = template.cloneWithAttribut(true); + + // After clone callBack function + if (typeof options.afterClone === "function") { + options.afterClone(source, clone); + } + + // Get source + clone.getSource = function() { + return source; + }; + + return clone; + + } + + /** + * Handle click on addForm button + */ + function clickOnAdd(event) + { + event.preventDefault(); + addForm(); + } + + /** + * Handle click on addNForm button + */ + function clickOnAddN(event) + { + event.preventDefault(); + if (addNInput.value !== '') { + addNForms(addNInput.attr('value')); + } + } + + /** + * Handle click on Remove current button + */ + function clickOnRemoveCurrent(event) + { + event.preventDefault(); + + // Before remove current callBack function + if (typeof options.beforeRemoveCurrent === "function") { + options.beforeRemoveCurrent(source); + } + + if (options.removeCurrentConfirmation) { + if ( confirm(options.removeCurrentConfirmationMsg) ) { + removeCurrentForm($(this).data('removableClone')); + } + } else { + removeCurrentForm($(this).data('removableClone')); + } + + // After remove current callBack function + if (typeof options.afterRemoveCurrent === "function") { + options.afterRemoveCurrent(source); + } + } + + /** + * Handle click on Remove last control + */ + function clickOnRemoveLast(event) + { + event.preventDefault(); + + if (options.removeLastConfirmation) { + if ( confirm(options.removeLastConfirmationMsg) ) { + removeLastForm(); + } + } else { + removeLastForm(); + } + + + } + + /** + * Handle click on Remove all control + */ + function clickOnRemoveAll(event) + { + event.preventDefault(); + + if (options.removeAllConfirmation) { + if ( confirm(options.removeAllConfirmationMsg) ) { + removeAllForms(); + } + } else { + removeAllForms(); + } + + + } + + function getOrSetTemplate(element, attrname){ + if(typeof element != "undefined"){ + var template=element.attr(attrname+"template"); + + if(template) { + return unescape(template); + } + var att=element.attr(attrname); + // Hide index occurrences inside the template (todo: better escaping method) + element.attr(attrname+"template", escape(att)); + return att; + } + return false; + } + + /** + * Get a form and normalize fields id and names to match the current position + */ + function normalizeFieldsForForm(form, index) + { + form.find(formFields).each(function(){ + var that = $(this) + ,idTemplateAttr = getOrSetTemplate(that,"id") + ,nameTemplateAttr = getOrSetTemplate(that, "name") + ,idAttr = that.attr("id") + ,nameAttr = that.attr("name") + + /* Normalize field name attributes */ + newNameAttr = nameTemplateAttr.replace(options.indexFormat, index); + that.attr("name", newNameAttr); + + /* Normalize field id attributes */ + newIdAttr = idTemplateAttr.replace(options.indexFormat, index); + + form.find("label[for='"+idAttr+"']").each(function(){ + $(this).attr("for", newIdAttr); + }); + that.attr("id", newIdAttr); + }); + } + + function normalizeLabelsForForm(form, index) + { + setLabelForForm(form, index+1); + } + + function setLabelForForm(form, label) + { + form.find(options.labelSelector).html(label); + return true; + } + + function getLabelForForm(form) + { + return form.find(options.labelSelector).html(); + } + + /** + * Show/Hide controls according to current state of the forms + */ + function normalizeControls() + { + // Remove buttons + if (hasForms()) { + + if (getFormsCount() == 1) { + removeAll.hideIf(); + removeLast.showIf(); + } else { + removeAll.showIf(); + removeLast.showIf(); + } + + // Remove current buttons + var removeCurrents = ''; + if (options.allowRemoveCurrent) { + removeCurrents = source.find(options.removeCurrentSelector); + if (canRemoveForm()) { + // Show remove current buttons of all forms + removeCurrents.show(); + } else { + removeCurrents.hide(); + } + } else { + // Hide all + removeCurrents = source.find(options.removeCurrentSelector); + removeCurrents.hide(); + } + + + + } else { + removeLast.hideIf(); + removeAll.hideIf(); + } + + // Add button + if (!canAddForm()) { + add.hideIf(); + addN.hideIf(); + } else { + add.showIf(); + addN.showIf(); + } + + // Remove buttons only enabled when can remove forms + if (!canRemoveForm()) { + removeLast.hideIf(); + removeAll.hideIf(); + } + + if ( + add.css('display') != 'none' + || addN.css('display') != 'none' + || removeAll.css('display') != 'none' + || removeLast.css('display') != 'none' + ) { + controls.show(); + } else { + controls.hide(); + } + } + + /** + * Show/hide noFormsMsg + */ + function normalizeForms() + { + if(hasForms()){ + + noFormsTemplate.hide(); + + if(options.continuousIndex) { + + var index=0 + , form=getFirstForm(); + + do{ + normalizeForm(form, index); + index++; + form = getNextForm(form); + }while (form!=false) + } + + + }else{ + noFormsTemplate.show(); + } + } + + function normalizeForm(form, index) + { + if(typeof form == "undefined"){ + return false; + } + if (typeof index == 'undefined') { + index=getIndex(); + } + + var idTemplate=getOrSetTemplate(form, "id"); + + // Normalize form id + if (form.attr("id")) { + form.attr("id", idTemplate + index); + } + + + // Normalize indexes for fields name and id attributes + normalizeFieldsForForm(form, index); + + // Normalize labels + normalizeLabelsForForm(form, index); + + // Normalize other possibles indexes inside html + if (form.html()!= null && form.html().indexOf(options.indexFormat) != -1) { + // Create a javascript regular expression object + var re = new RegExp(options.indexFormat,"ig"); + // Replace all index occurrences inside the html + form.html(form.html().replace(re, index)); + } + + // Remove current form control + var removeCurrent = form.find(options.removeCurrentSelector); + (options.allowRemoveCurrent) ? removeCurrent.show() : removeCurrent.hide(); + + return form; + } + + /** + * Normalize all (Controls, Forms) + */ + function normalizeAll() + { + normalizeForms(); + normalizeControls(); + } + + /** + * Add a new form to the collection + * + * @parameter normalize: avoid normalize all forms if not necessary + */ + function addForm(normalizeAllafterAdd, form) + { + if (typeof normalizeAllafterAdd == 'undefined') { + normalizeAllafterAdd = true; + } + + if (typeof form == 'undefined') { + form = false; + } + + // Before add callBack function + if (typeof options.beforeAdd === "function") { + options.beforeAdd(source); + } + + var newForm = false; + + // Pre-generated form + if (form) { + if ( typeof(form) == 'string' ) { + newForm = $('#' + form); + } + else if ( typeof(form) == 'object' ) { + newForm = form; + } else { + return false; + } + + newForm.remove(); + + } + // Cloned Form + else { + // Get template clone + newForm = cloneTemplate(); + } + + if (canAddForm() && newForm) { + + newForm = normalizeForm(newForm); + + + // Remove current control + var removeCurrentBtn = newForm.find(options.removeCurrentSelector).first(); + + removeCurrentBtn.click(clickOnRemoveCurrent); + removeCurrentBtn.data('removableClone', newForm); + + + // Index + newForm.data('formIndex', getIndex()); + + // Linked references (separators and forms) + newForm.data('previousSeparator',false); + newForm.data('nextSeparator',false); + newForm.data('previousForm',false); + newForm.data('nextForm',false); + + // Link references? + if (hasForms()) { + + var lastForm = getLastForm(); + + // Form references + if(lastForm){ + lastForm.data('nextForm',newForm); + newForm.data('previousForm',lastForm); + + // Separator references + if (options.separator) { + var separator = getSeparator(); + separator.insertAfter(lastForm); + lastForm.data('nextSeparator',separator); + newForm.data('previousSeparator',separator); + } + } + + + + } + + (options.insertNewForms == 'after') ? newForm.insertBefore(noFormsTemplate) : newForm.insertAfter(noFormsTemplate); + + // Nested forms + if (options.nestedForms.length > 0) { + + var x = 0; + var nestedForms = []; + + for(x in options.nestedForms) { + + if (typeof(options.nestedForms[x].id) != 'undefined' && typeof(options.nestedForms[x].options) != 'undefined') { + options.nestedForms[x].isNestedForm = true; + options.nestedForms[x].parentForm = source; + var id = options.nestedForms[x].id.replace(options.indexFormat,newForm.data('formIndex')); + var nestedForm = $('#' + id).sheepIt(options.nestedForms[x].options); + + nestedForms.push(nestedForm); + } + } + newForm.data('nestedForms',nestedForms); + } + + extendForm(newForm); + + forms.push(newForm); + + /** + * If index has to be continuous, + * all items are reindexed/renumbered using + * normalizeAll() after add a new form clone + */ + if (normalizeAllafterAdd || options.continuousIndex) { + normalizeAll(); + } + + // After add callBack function + if (typeof options.afterAdd === "function") { + options.afterAdd(source, newForm); + } + + return true; + + } else { + return false; + } + + } + + function addNForms(n, normalize) + { + if (typeof n != 'undefined') { + n = parseFloat(n); + var x = 1; + + for(x=1; x<=n; x++) { + addForm(normalize); + } + } + } + + function removeLastForm(normalize) + { + if (typeof normalize == 'undefined') { + normalize = true; + } + + if (canRemoveForm()) { + removeForm(); + + if (normalize) { + normalizeAll(); + } + return true; + + } else { + return false; + } + + } + + function removeAllForms(normalize) + { + if (typeof normalize == 'undefined') { + normalize = true; + } + + if (canRemoveAllForms()) { + var x = []; + forms.each(function(f){ + removeForm(f); + }); + + if (normalize) { + normalizeAll(); + } + return true; + } else { + return false; + } + + } + + function removeCurrentForm(formToRemove, normalize) + { + if (typeof normalize == 'undefined') { + normalize = true; + } + + if (canRemoveForm()) { + removeForm(formToRemove); + + if (normalize) { + normalizeAll(); + } + return true; + } else { + return false; + } + } + + /** + * Remove form from the index and DOM + */ + function removeForm(formToRemove) + { + // If no form provided then remove the last one + if (typeof formToRemove == 'undefined') { + formToRemove = getLastForm(); + } + + if(!formToRemove){ + return false; + } + + index = formToRemove.data('formIndex'); + + /** + * Remove separator? + */ + // Two + if (formToRemove.data('previousSeparator') && formToRemove.data('nextSeparator')) { + formToRemove.data('previousSeparator').remove(); + formToRemove.data('previousForm').data('nextSeparator',formToRemove.data('nextSeparator')); + } + // before + else if(formToRemove.data('previousSeparator') && !formToRemove.data('nextSeparator')) { + formToRemove.data('previousSeparator').remove(); + formToRemove.data('previousForm').data('nextSeparator',false); + } + // after + else if(!formToRemove.data('previousSeparator') && formToRemove.data('nextSeparator')) { + formToRemove.data('nextSeparator').remove(); + formToRemove.data('nextForm').data('previousSeparator',false); + } + + // Update forms references + if (formToRemove.data('previousForm')) { + formToRemove.data('previousForm').data('nextForm',formToRemove.data('nextForm')); + } + + if (formToRemove.data('nextForm')) { + formToRemove.data('nextForm').data('previousForm',formToRemove.data('previousForm')); + } + + // From index + forms[index] = false; + //forms.splice(index, index+1); + // From DOM + formToRemove.remove(); + + return true; + + } + + + + /*---------------- ITERATOR METHODS ----------------*/ + + /** + * Gets the current internal pointer + */ + function current() + { + return ip; // false or integer + } + + /** + * Increment the internal pointer + */ + function next() + { + if (ip !== false) { + + if (forms.length > 1) { + var i = 0; + var init = parseFloat(ip+1); + + for (i=init; i 1) { + + var i = 0; + var init = parseFloat(ip-1); + for (i=init; i>=0; i--) { + + if (forms[i]) { + ip = i; + return true; + } + } + return false; + } else { + return false; + } + + } else { + return false; + } + } + + /** + * Brings the internal pointer to the first element + */ + function first() + { + ip = false; + if (forms.length > 0) { + var x = 0; + for (x in forms) { + + if (forms[x]) { + ip = x; + return true; + } + } + return false; + } else { + return false; + } + } + + /** + * Brings the internal pointer to the last element + */ + function last() + { + ip = false; + if (forms.length > 0) { + + if (forms[forms.length-1]) { + ip = forms.length-1; + return true; + } else { + var i = 0; + for (i=(forms.length-1); i>=0 ; i--) { + + if (forms[i]) { + ip = i; + return true; + } + } + return false; + } + } else { + return false; + } + } + + /** + * Count the current elements + */ + function count() + { + if (forms.length > 0) { + var count = 0; + var x = []; + for (x in forms) { + if (forms[x] ) { + count++; + } + } + return count; + } else { + return 0; + } + } + + /** + * Sets the pointer to a new position + */ + function setPointerTo(position) + { + if (typeof position != 'undefined') { + ip = getIndexForPosition(position); + if (ip !== false) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Get the "real" index for a given position + */ + function getIndexForPosition(position) + { + var x = 0; + var count = 0; + var index = false; + + for (x in forms) { + if (forms[x]) { + count++; + // get index for position + if (position == count) { + index = x; + } + } + } + + return index; + } + + function getPositionForIndex(index) + { + var x = 0; + var position = 0; + + for (x=0; x<=index; x++) { + if (forms[x]) { + position++; + } + } + return position; + } + + /** + * Get the current index (Forms array length) + */ + function getIndex() + { + return forms.length; + } + + /*---------------- /ITERATOR METHODS ----------------*/ + + function getFormsCount() + { + return count(); + } + + function getFirstForm() + { + if (first() !== false) { + return getCurrentForm(); + } else { + return false; + } + } + + function getLastForm() + { + if (last() !== false) { + return getCurrentForm(); + } else { + return false; + } + } + + function getNextForm(form) + { + if (form) { + return form.data('nextForm'); + } else if(current() !== false) { + if (next() !== false) { + return getCurrentForm(); + } else { + return false; + } + } else { + return false; + } + } + + function getPreviousForm(form) + { + if (form) { + return form.data('previousForm'); + } else if(current() !== false) { + if (previous() !== false ) { + return getCurrentForm(); + } else { + return false; + } + } else { + return false; + } + } + + /** + * Get the current form based on the interal pointer + */ + function getCurrentForm() + { + if ( current() !== false) { + return forms[current()]; + } else { + return false; + } + } + + /** + * Get a form by its position + */ + function getForm(position) + { + if (hasForms()) { + if (typeof(position) != 'undefined') { + setPointerTo(position); + return getCurrentForm(); + } + // Last form + else { + return getLastForm(); + } + } else { + return false; + } + } + + /** + * Get active forms + */ + function getForms() + { + if (hasForms()) { + first(); + + var x = 0; + var activeForms = []; + for (x=0; x 0) ? true : false; + } + + function canAddForm() + { + if (options.maxFormsCount == 0) { + return true; + } else { + return (getFormsCount() < options.maxFormsCount) ? true : false; + } + } + + /** + * Checks if can remove any form + */ + function canRemoveForm() + { + return (getFormsCount() > options.minFormsCount) ? true : false; + } + + function canRemoveAllForms() + { + return (options.minFormsCount == 0) ? true : false; + } + + function isInDom(object) + { + if ( $("#" + object.attr('id')).length > 0 ) { + return true; + } else { + return false; + } + } + + /** + * Controls the whole process of data injection + * + */ + function fillData(index, values) + { + + var form = ''; + + // Position + if (typeof(index) == 'number') { + + // Correction of index to position + index++; + + // Need more forms? + if ((index) > getFormsCount()) { + addForm(); + } + + form = getForm(index); + + fillForm(form, values); + } + // Form Id + else if(typeof(index) == 'string') { + + form = $('#'+index); + fillForm(form, values); + } + + if (typeof options.afterFill === "function") { + options.afterFill(source, form, values); + } + + } + + function fillForm(form, data) + { + var x = 0; + + // For each element, try to get the correct field or fields + $.each(data, function(index, value) { + + var formId = source.attr('id'); + var formIndex = form.data('formIndex'); + + + + // Replace form Id and form Index with current values + if (index.indexOf('#form#') != -1 || index.indexOf('#index#') != -1) { + index = index.replace('#form#', formId); + index = index.replace('#index#', formIndex); + } else { + index = formId + '_' + formIndex + '_' + index; + } + + + + /** + * Search for field (by id, by name, etc) + */ + + // Search by id + var field = form.find(':input[id="' + index + '"]'); + + // Search by name + if (field.length == 0) { + + // Search by name + field = form.find(':input[name="' + index + '"]'); + + if (field.length == 0) { + // Search by name array format + field = form.find(':input[name="' + index + '[]"]'); + } + } + + + + // Field was found + if (field.length > 0) { + + // Multiple values? + var mv = false; + if (typeof(value) == 'object') { + mv = true; + } + + // Multiple fields? + var mf = false; + if (field.length > 1) { + mf = true; + } + + if (mf) { + + if (mv) { + + var fieldsToFill = []; + fieldsToFill['fields'] = []; + fieldsToFill['values'] = []; + + x = 0; + /*for (x in value) { + fieldsToFill['fields'].push(field.filter('[value="'+ value[x] +'"]')); + fieldsToFill['values'].push(value[x]); + }*/ + if(value != null){ + value.each(function(ind,val){ + fieldsToFill['fields'].push(field.filter('[value="'+ val +'"]')); + fieldsToFill['values'].push(val); + }); + } + + + x = 0; + fieldsToFill['fields'].each(function(ind,fields){ + fillFormField(fieldsToFill['fields'][ind] , fieldsToFill['values'][ind]); + }); + /*for (x in fieldsToFill['fields']) { + fillFormField(fieldsToFill['fields'][x] , fieldsToFill['values'][x]); + }*/ + } else { + fillFormField( field.filter('[value="'+ value +'"]', value) ); + } + } else { + if (mv) { + x = 0; + if(value != null){ + value.each(function(ind,val){ + fillFormField(field, val); + }); + } + /*for (x in value) { + fillFormField(field, value[x]); + }*/ + } else { + fillFormField(field, value); + } + } + } + // Field not found in this form try search inside nested forms + else { + if ( typeof(form.data('nestedForms')) != 'undefined') { + if (form.data('nestedForms').length > 0) { + x = 0; + for (x in form.data('nestedForms')) { + + if (index == form.data('nestedForms')[x].attr('id') && typeof(value) == 'object') { + form.data('nestedForms')[x].inject(value); + } + } + + } + } + } + + }); + + + } + + function fillFormField(field, value) + { + var type = field.attr('type'); + + // hidden, text, password + if (type == 'text' || type == 'hidden' || type == 'password') { + field.attr('value', value); + return true; + } + // textarea + else if(type == 'textarea') { + field.text(value); + return true; + } + // checkbox, radio button + else if(type == 'checkbox' || type == 'radio') { + field.attr("checked", "checked"); + return true; + } + // select-one, select-multiple + else if (type == 'select-one' || type == 'select-multiple') { + field.find("option").each(function() { + if($(this).text() == value || $(this).attr("value") == value) { + $(this).attr("selected", "selected"); + } + }); + return true; + } else { + return false; + } + } + + function hasSeparator() + { + if (options.separator != '') { + return true; + } else { + return false; + } + } + + function getSeparator() + { + if (hasSeparator()) { + return $(options.separator); + } else { + return false; + } + } + + function setOptions(newOptions) + { + options = []; + options = $.extend(defaults, newOptions); + normalizeOptions(options); + } + + function getOptions() + { + return options; + } + + function initialize() + { + // Hide forms during initialization + source.hide(); + + /** + * Controls + */ + add = $(options.addSelector); + addN = $(options.addNSelector); + addNInput = $(options.addNInputSelector); + addNButton = $(options.addNButtonSelector); + removeLast = $(options.removeLastSelector); + removeCurrent = $(options.removeCurrentSelector); + removeAll = $(options.removeAllSelector); + controls = $(options.controlsSelector); + + if (add.length == 0) { + options.allowAdd = false; + } + if (addN.length == 0) { + options.allowAddN = false; + } + if (removeLast.length == 0) { + options.allowRemoveLast = false; + } + if (removeAll.length == 0) { + options.allowRemoveAll = false; + } + + // Extend basic controls with new methods used inside this plugin + extendControl(add, options.allowAdd, clickOnAdd); + extendControl(addN, options.allowAddN, clickOnAddN, addNButton); + extendControl(removeLast, options.allowRemoveLast, clickOnRemoveLast); + extendControl(removeAll, options.allowRemoveAll, clickOnRemoveAll); + + // Initialize controls + add.init(); + addN.init(); + removeLast.init(); + removeAll.init(); + + /** + * Templates + */ + templateForm = $(options.formTemplateSelector); + noFormsTemplate = $(options.noFormsTemplateSelector); + + // Get the template for clonning + //templateForm.show(); + template = templateForm.cloneWithAttribut(true); + templateForm.remove(); + + /** + * Forms initialization + */ + var x = 0; + + // Pregenerated forms + if (options.pregeneratedForms.length > 0) { + x = 0; + for(x in options.pregeneratedForms) { + addForm(false,options.pregeneratedForms[x]); + } + } + + // Initial forms + if ( options.iniFormsCount > getFormsCount()) { + x = 0; + var b = options.iniFormsCount-getFormsCount(); + for (x=1; x<=b; x++) { + addForm(false); + } + + } + + /** + * Data injection + */ + if(options.data){ + source.inject(options.data); + } + + normalizeAll(); + + source.show(); + } + + /** + * Extend passed control with new methods used by this plugin + */ + function extendControl(control, allowControlOption , onClickFunction, onClickSubControl) + { + /** + * onClickSubControl es utilizado cuando el control principal no es el que recibe el click + */ + if (typeof(onClickSubControl) == 'undefined') { + onClickSubControl = false; + } + + $.extend( control, { + hideIf : function(duration, callback) { + if (allowControlOption) { + control.hide(duration, callback); + } + }, + showIf: function(duration, callback) { + if (allowControlOption) { + control.show(duration, callback); + } + }, + init: function() { + if (allowControlOption) { + // Click event + if (onClickSubControl) { + onClickSubControl.click(onClickFunction); + } else { + control.click(onClickFunction); + } + control.show(); + } else { + control.hide(); + } + } + }); + } + + /** + * Extends source object with many useful methods, + * used to control sheepIt forms with javascript + */ + function extendSource(source) + { + // API + $.extend( source, { + + /* ----- Controls ----- */ + getAddControl: function() { + return add; + }, + getAddNControl: function() { + return addN; + }, + getRemoveLastControl: function() { + return removeLast; + }, + getRemoveAllControl: function() { + return removeAll; + }, + + /* ----- Options ----- */ + getOptions: function() { + return getOptions(); + }, + getOption: function(option) { + return options[option]; + }, + setOption: function(option, value) { + if (typeof(option) != 'undefined' && typeof(value) != 'undefined') { + options[option] = value; + return options[option]; + } else { + return false; + } + }, + + /* ----- Forms ----- */ + // Get all Forms + getForms: function() { + return getForms(); + }, + // Alias of getForms + getAllForms: function() { + return getForms(); + }, + getForm: function(val) { + if (typeof(val) != 'undefined') { + val++; + } + return getForm(val); + }, + getLastForm: function() { + return getForm(); + }, + getFirstForm: function() { + first(); + return getCurrentForm(); + }, + addForm: function() { + return addForm(); + }, + addNForms: function(n) { + return addNForms(n); + }, + // Number of active forms + getFormsCount: function() { + return getFormsCount(); + }, + hasForms: function() { + return hasForms(); + }, + canAddForm: function() { + return canAddForm(); + }, + canRemoveAllForms: function() { + return canRemoveAllForms(); + }, + // Can remove a form? + canRemoveForm: function() { + return canRemoveForm(); + }, + removeAllForms: function() { + return removeAllForms(); + }, + removeLastForm: function() { + return removeLastForm(); + }, + removeFirstForm: function() { + first(); + return removeForm(getCurrentForm()); + }, + removeForm: function(val) { + if (typeof(val) != 'undefined') { + val++; + } + return removeForm(getForm(val)); + }, + + /* ----- Advanced ----- */ + inject: function(data) { + + // Loop over each data using a Proxy (function , context) + $.each(data, $.proxy( fillData, source )); + } + + }); + + } + + /** + * Extends cloned forms with many useful methods, + * used to control each form with javascript + */ + function extendForm(form) + { + // API + $.extend( form, { + setLabel: function(newLabel) { + return setLabelForForm(form, newLabel); + }, + getLabel: function() { + return getLabelForForm(form); + }, + inject: function(data) { + fillForm(form, data); + }, + getNestedForms: function() { + return form.data('nestedForms'); + }, + getNestedForm: function(val) { + return form.data('nestedForms')[val]; + }, + getPosition: function() { + return getPositionForIndex(form.data('formIndex')); + }, + getPreviousForm: function() + { + return getPreviousForm(form); + }, + getNextForm: function() + { + return getNextForm(form); + }, + removeForm: function() + { + return removeForm(form); + } + }); + } + + /** + * Normalize options + */ + function normalizeOptions(options) + { + // Normalize limits options + if (options.maxFormsCount > 0) { + if (options.maxFormsCount < options.minFormsCount) { + options.maxFormsCount = options.minFormsCount; + } + if (options.iniFormsCount < options.minFormsCount || options.iniFormsCount > options.maxFormsCount) { + options.iniFormsCount = options.minFormsCount; + } + } else { + if (options.iniFormsCount < options.minFormsCount) { + options.iniFormsCount = options.minFormsCount; + } + } + + if (!canRemoveAllForms()) { + options.allowRemoveAll = false; + } + } + + + /** + * Gets the first element of the collection and decorates with jquery + */ + var source = $(this).first(); + + // Extend source with useful methods + extendSource(source); + + var add, + addN, + addNInput, + addNButton, + removeLast, + removeCurrent, + removeAll, + controls, + template, + templateForm, + noFormsTemplate, + formFields = "input, checkbox, select, textarea", + forms = [], + ip = false, // Internal ip + // Default options + defaults = { + + // Controls selectors + addSelector: '#' + $(this).attr("id") + '_add', + addNSelector: '#' + $(this).attr("id") + '_add_n', + addNInputSelector: '#' + $(this).attr("id") + '_add_n_input', + addNButtonSelector: '#' + $(this).attr("id") + '_add_n_button', + removeLastSelector: '#' + $(this).attr("id") + '_remove_last', + removeCurrentSelector: '#' + $(this).attr("id") + '_remove_current', + removeAllSelector: '#' + $(this).attr("id") + '_remove_all', + controlsSelector: '#' + $(this).attr("id") + '_controls', + labelSelector: '#' + $(this).attr("id") + '_label', + + // Controls options + allowRemoveLast: true, + allowRemoveCurrent: true, + allowRemoveAll: false, + allowAdd: true, + allowAddN: false, + + // Confirmations + removeLastConfirmation: false, + removeCurrentConfirmation: false, + removeAllConfirmation: true, + removeLastConfirmationMsg: 'Are you sure?', + removeCurrentConfirmationMsg: 'Are you sure?', + removeAllConfirmationMsg: 'Are you sure?', + + // Templates + formTemplateSelector: '#' + $(this).attr("id") + '_template', + noFormsTemplateSelector: '#' + $(this).attr("id") + '_noforms_template', + separator: '
', + + // Limits + iniFormsCount: 1, + maxFormsCount: 20, // 0 = no limit + minFormsCount: 1, + incrementCount: 1 , // add N forms at one time + noFormsMsg: 'No forms to display', + + // Id and names management + indexFormat:'#index#', + + // Advanced options + data: [], // A JSON based representation of the data which will prefill the form (equivalent of the inject method) + pregeneratedForms: [], + nestedForms: [], + isNestedForm: false, + parentForm: {}, + beforeClone: function() {}, + afterClone: function() {}, + beforeAdd: function() {}, + afterAdd: function() {}, + afterFill: function() {}, + afterRemoveCurrent: function(){}, + beforeRemoveCurrent: function(){}, + insertNewForms: 'after', + continuousIndex: true //Keep index continuous and starting from 0 + }; + + setOptions(options); + initialize(); + + return source; + }; + + /** + * JQuery original clone method decorated in order to fix an IE < 8 issue + * where attributs especially name are not copied + */ + jQuery.fn.cloneWithAttribut = function( withDataAndEvents ){ + if ( jQuery.support.noCloneEvent ){ + return $(this).clone(withDataAndEvents); + }else{ + $(this).find("*").each(function(){ + $(this).data("name", $(this).attr("name")); + }); + var clone = $(this).clone(withDataAndEvents); + + clone.find("*").each(function(){ + $(this).attr("name", $(this).data("name")); + }); + + return clone; + } + }; + +})(jQuery);