// Expromptum JavaScript Library // Copyright Art. Lebedev | http://www.artlebedev.ru/ // License: BSD | http://opensource.org/licenses/BSD-3-Clause // Author: Vladimir Tokmakov | vlalek // Updated: 2015-09-10 (function(window,$){ if(window.expromptum){return} window.expromptum=window.xP=(function(undefined){ var xP=function(params,parent){ if(!params){ params='[data-xp],[data-expromptum]'; for(var i=0,ii=xP_controls_registered.length;i-1){ this.splice(i,1) } return this }; result.filter=function(handler){ return this.each(handler,true) }; result.each=function(handler,_filter){ var i=0,ii=this.length,current,result; while(i\@\/\~\&\=])/g; xP.locale={ init:function(){ var t=xP.locale.number; $.extend( t, { format:{ decimal:/\./, grouping:/(\d\d|\d(?=\d{4}))(?=(\d{3})+([^\d]|$)())/g }, unformat:{ decimal:new RegExp('[\\.\\'+t.decimal+']'), grouping:new RegExp('\\'+t.grouping,'g') } } ) }, destroy:function(){ }, abbr:'ru', number:{decimal:',',grouping:' '}, date:'dd.mm.yy', month:[ {abbr:'янв',name:'Январь',name_genitive:'января'}, {abbr:'фев',name:'Февраль',name_genitive:'февраля'}, {abbr:'мар',name:'Март',name_genitive:'марта'}, {abbr:'апр',name:'Апрель',name_genitive:'апреля'}, {abbr:'мая',name:'Май',name_genitive:'мая'}, {abbr:'июн',name:'Июнь',name_genitive:'июня'}, {abbr:'июл',name:'Июль',name_genitive:'июля'}, {abbr:'авг',name:'Август',name_genitive:'августа'}, {abbr:'сен',name:'Сентябрь',name_genitive:'сентября'}, {abbr:'окт',name:'Октябрь',name_genitive:'октября'}, {abbr:'ноя',name:'Ноябрь',name_genitive:'ноября'}, {abbr:'дек',name:'Декабрь',name_genitive:'декабря'} ], first_day:1, weekday:[ {abbr:'Пн',name:'Понедельник'}, {abbr:'Вт',name:'Вторник'}, {abbr:'Ср',name:'Среда'}, {abbr:'Чт',name:'Четверг'}, {abbr:'Пт',name:'Пятница'}, {abbr:'Сб',name:'Суббота'}, {abbr:'Вс',name:'Воскресенье'} ], prev_month:'Предыдущий', next_month:'Следующий', yesterday:'Вчера', today:'Сегодня', tomorrow:'Завтра' }; xP.locale.init(); xP.base=xP.register({name:'xP.base',prototype:{ init:function(params){ this._.on_destroy=new xP.list(); this._.on_change=new xP.list(); $.extend(this,params) }, destroy:function(handler,remove){ if(!arguments.length){ clearTimeout(this._.change_inquiry); var that=this; this._.on_destroy.each(function(){ this.call(that) }) }else{ if(remove){ this._.on_destroy.remove(handler) }else{ this._.on_destroy.append(handler) } } return this }, change:function(handler,remove){ if(!arguments.length){ if(!this._.change_inquiry){ clearTimeout(this._.change_inquiry); var that=this; that._.change_inquiry=xP.after(function(){ that._.change_inquiry=null; that._.on_change.each(function(){ this.call(that) }) }) } }else{ if(remove){ this._.on_change.remove(handler) }else{ this._.on_change.append(handler) } } return this }, param:function(name,value){ if(arguments.length===2){ this[name]=value } return this[name] }, _param:function(name,value){ if(arguments.length===2){ this._[name]=value } return this._[name] } }}); var xP_controls_registered=[]; xP.controls={ register:function(params){ var name=params.name; if(!params.prototype){ params.prototype={} } params.prototype.type=name; this[params.name]=xP.register( $.extend( params, { name:'expromptum.controls.'+name, base:$.type(params.base)==='string' ?this[params.base] :params.base } ) ); if(params.prototype&¶ms.prototype.element_selector){ xP_controls_registered.push(name) } }, init:function($elements){ var result=new xP.list(),that=this; $elements.each(function(){ var $element=$(this),control=that.link($element); if(!control){ var params=$element.data('xp') ||$element.data('expromptum'); if($.type(params)==='string'){ if(!params.match(/^^\s*\{/)){ params='{'+params+'}' } params=eval( '(function(){return ' +params .replace(/([\{,])\s*do\s*:/g,'$1\'do\':') +'})()' ) } $element .removeAttr('data-xp') .removeAttr('data-expromptum'); if(!params){ params={} } if(!params.type){ var i=xP_controls_registered.length; while(i--){ if( $element.is( xP.controls[xP_controls_registered[i]] .prototype.element_selector ) ){ params.type=xP_controls_registered[i]; break } } } if( xP.controls[params.type] &&xP.controls[params.type].base ){ params.$element=$element; control=new xP.controls[params.type](params) } } if(control){ result.append(control) } }); return result }, link:function($element,control){ if(control){ $element.data('expromptum.control',control); $element[0].expromptum=control }else{ return $element.data('expromptum.control') } } }; xP.controls.register({name:'_item',base:xP.base,prototype:{ init:function(params){ xP.controls._item.base.init.apply(this,arguments); if(!this.$element){ this.create() } xP.debug('controls','control',this.type,this.$element,this); if(!this.$container&&this.container_selector){ this.$container =this.$element.parents(this.container_selector).first() } if(!this.$container||!this.$container.length){ this.$container=this.$element } var a=['disabled','required','autofocus','min','max','step'], i=a.length,v; while(i--){ v=this.$element.attr(a[i]); if(v!==undefined&&!this[a[i]]!==undefined){ this[a[i]]=v } } if(this.autofocus){ this.$element.focus() } var that=this; this._init_val(); if(this.disabled||this.enabled===false){ this.disabled=false; xP.after(function(){ that.disable() }) } xP.after(function(){ that.change(); that._init_val() }); if(!this._.parent){ this.$container.parentsUntil('body').each(function(){ var control=xP.controls.link($(this)); if(control){ that._.parent=control; return false } }) } if(this._.parent&&!(this instanceof xP.controls.form)){ this._.parent.children().each(function(){ if(that.$container.has(this.$container)[0]){ that._.parent._.children.remove(this); this._.parent=that; that._.children.append(this) } }); this._.no_root_dependencies =this._.parent._.no_root_dependencies; this._.parent._.children.append(this); this._.root=this._.parent._.root }else{ this._.root=xP.root||this } xP.controls.link(this.$element,this); xP.controls.link(this.$container,this); this.name=this.$element.attr('name')||this.name; if(xP.repeats){ xP.repeats.init(this) } xP.dependencies.init(this) }, remove:function(){ var $container=this.$container, destroy_with_children=function(parent){ if(parent.children){ parent.children().each(function(){ destroy_with_children(this) }) } parent.destroy() }; destroy_with_children(this); $container.remove(); var parent=this.parent(); if(parent){ parent.change() } }, destroy:function(handler,remove){ xP.controls._item.base.destroy.apply(this,arguments); if(!arguments.length){ if(this._.parent){ this._.parent._.children.remove(this) } this.$container =this.$element =null } return this }, parent:function(){ return this._.parent }, root:function(){ return this._.root }, _init_val:function(){ this._.initial_value =this._.value =this.val() }, val:function(value){ if(!arguments.length){ return '' }else{ this.change(); return this } }, disable:function(disabled){ disabled=!arguments.length||disabled; if(this.disabled!==disabled){ if(disabled){ this.$element.add( this.$container.addClass( this.container_disabled_class ) ).attr('disabled',true) }else{ var parent=this; while((parent=parent.parent())&&parent!=this){ if(parent.disabled){ return this } } this.$element.add( this.$container.removeClass( this.container_disabled_class ) ).removeAttr('disabled') } this.disabled=disabled; this.change() } return this }, container_disabled_class:'disabled', _get_html:function(){ return this.html } }}); xP.controls.register({name:'html',base:'_item',prototype:{ element_selector:'.xp_html', val:function(value){ if(!arguments.length){ return this.disabled?undefined:this.$element.html() }else{ this.$element.html(value); this.change(); return this } } }}); xP.controls.register({name:'_parent',base:'_item',prototype:{ element_selector:'.xp', init:function(params){ this.changed={}; this._.children=new xP.list(); xP.controls._parent.base.init.apply(this,arguments); this._.$pocus=this.$element; this._.children_values={}; var parent4values=this._.parent||this._.root; while( !parent4values.name &&!parent4values.repeat &&parent4values._.parent &&parent4values!==this._.root ){ parent4values=parent4values._.parent } this._.parent4values=parent4values }, children:function(){ return this._.children }, destroy:function(handler,remove){ if(!arguments.length){ this._.parent4values._unsave_val(this) } return xP.controls._parent.base.destroy.apply(this,arguments) }, disable:function(disabled){ disabled=!arguments.length||disabled; if(this.disabled!==disabled){ xP.controls._parent.base.disable.apply(this,arguments); if(this.disabled){ this._.parent4values._unsave_val(this) } this._.children.each(function(){ this.disable(disabled) }) } return this }, val:function(value,_suffix){ if(!arguments.length){ return this._.children_values }else{ if(this.repeat){ if($.type(value)!=='array'){ value=[value] } var siblings=this.repeat.children(), ii=value.length, sibling; while(siblings.length>ii){ this.repeat.remove(siblings[siblings.length-1]) } for(var i=0;i=0&&ii') .parents('.'+this.selectors_class) } this.close(); this.$select=$('') .insertBefore(this.$selectors); new xP.dependencies.computed( { from:this.options, on:function(){ var html=''; that.options.first()._.group.siblings.each(function(){ if(this.$element.is(':checked')){ html+='' +this.$label.html()+'' } }); return html } }, new xP.controls.html({ $element:this.$select, type:'html' }) ); this.$select.on('mouseup keypress',function(ev){ if( !that.disabled &&( ev.type==='mouseup' ||ev.keyCode===13 ||ev.keyCode===40 ) ){ if(that.$selectors.hasClass('hidden')){ that.open(); return false } } }); this.$selectors.on('keydown',function(ev){ if(ev.keyCode===13||ev.keyCode===27){ that.close(); that.$select.focus(); return false } }).on('mouseup',function(){ return false }) }, selectors_class:'selectors', select_class:'select', open:function(){ if(xP.controls.opened){ xP.controls.opened.close() } xP.controls.opened=this; var that=this; this.$selectors.removeClass('hidden'); if(this.options.first()._.group.selected){ this.options.first()._.group.selected.$element.focus() }else{ this.options.first().$element.focus() } return this }, close:function(){ xP.controls.opened=null; this.$selectors.addClass('hidden'); return this } }}); $(document).bind('mouseup.expromptum_controls_opened',function(ev){ if(xP.controls.opened){ xP.controls.opened.close() } }); xP.controls.register({name:'_option',base:'_field',prototype:{ container_selector:'.option', init:function(params){ xP.controls._option.base.init.apply(this,arguments); if(!this.root()._param('_option')){ this.root()._param('_option',{}) } if(!this.root()._param('_option')[this.name]){ this.root()._param('_option')[this.name] ={siblings:new xP.list(),enabled_options:new xP.list()} } this._.group=this.root()._param('_option')[this.name]; this._.group.siblings.append(this); this.selected=null; this._init_val() }, destroy:function(handler,remove){ if(!arguments.length){ if(this._.group.selected===this){ this._.group.selected=null } this.disable(); this._.group.siblings.remove(this) } return xP.controls._option.base.destroy.apply(this,arguments) }, append:function(params){ if($.type(params)!=='array'){ params=[params] } var i=0,ii=params.length,html='',id; for(;i' } return xP($(html).insertAfter(this.$container).find('input')) }, change_events:'change', change:function(handler,remove){ this.select(this.$element.is(':checked'),true); xP.controls._option.base.change.apply(this,arguments); return this }, _init_val:function(){ if(this.selected){ this.$container.addClass(this.container_initial_selected_class) } xP.controls._option.base._init_val.apply(this,arguments) }, container_initial_selected_class:'initial_selected', container_selected_class:'selected', val:function(value){ if(!arguments.length){ return!this.selected ?'' :xP.controls._option.base.val.apply(this,arguments) }else if($.type(value)==='array'){ var i=value.length; while(i--){ if(this.$element[0].value==value[i]){ break } } this.select(i>-1) }else{ this.select(this.$element[0].value==value) } return this }, select:function(selected,_onchange){ selected=!arguments.length||selected; if(this.selected!==selected){ this.selected=selected; this.$container.toggleClass( this.container_selected_class, selected ); if(selected){ this.$element.attr('checked',true); this.$element[0].checked=true }else{ this.$element.removeAttr('checked') } if(!_onchange){ this.change() } } return this }, disable:function(disabled,dependence){ if(dependence&&dependence.values!==undefined){ if(!this._.group.enable_options){ this._.group.enabled_options.length=0 } if(!disabled){ this._.group.enabled_options.append(this) }else if(this._.group.enabled_options.index(this)==-1){ this.disable(true) } clearTimeout(this._.group.enable_options); var that=this; this._.group.enable_options=xP.after(function(){ that._.group.enable_options=null; that._.group.enabled_options.each(function(i){ this.disable(false) }) }); return this }else{ return xP.controls._option.base.disable.apply(this,arguments) } } }}); xP.controls.register({name:'radio',base:'_option',prototype:{ element_selector:'input[type=radio]', disable:function(disabled){ disabled=!arguments.length||disabled; if(this.disabled!==disabled){ xP.controls.radio.base.disable.apply(this,arguments); if(disabled){ if(this.selected){ var that=this; this._.group.siblings.each(function(){ if(!this.disabled&&this!==that){ this.select(); return false } }) } }else if( this._.group.selected &&this._.group.selected.disabled &&this._.group.selected!=this ){ this.select(); this.change() } }else{ xP.controls.radio.base.disable.apply(this,arguments) } return this }, select:function(selected,_onchange){ selected=!arguments.length||selected; if(this.selected!==selected){ if(selected&&this._.group){ var that_selected=this._.group.selected; this._.group.selected=this; if(that_selected){ that_selected.select(false) } } xP.controls.radio.base.select.apply(this,arguments) } return this } }}); xP.controls.register({name:'checkbox',base:'_option',prototype:{ element_selector:'input[type=checkbox]' }}); xP.controls.register({name:'email',base:'_field',prototype:{ element_selector:'.email input,input.email', valid:/^\S+@\S+\.\S{2,}$/ }}); xP.controls.register({name:'phone',base:'_field',prototype:{ element_selector:'.phone input,input.phone', valid:/^(?=[^()]*\(([^()]*\)[^()]*)?$|[^()]*$)(?=[\s(]*\+[^+]*$|[^+]*$)([-+.\s()]*\d){10,18}$/ }}); xP.controls.register({name:'_secret',base:'_field',prototype:{ init:function(params){ xP.controls._secret.base.init.apply(this,arguments); this.$secret=$( $('
') .append(this.$element.clone().hide()) .html() .replace(/\s+(type|id)\s*=\s*[^\s>]+/g,'') ).insertAfter(this.$element); this.$element.removeAttr('name'); xP.controls.link(this.$secret,this) }, change:function(handler,remove){ if(!arguments.length&&this.$secret){ this.$secret.val(this.val()) } return xP.controls._secret.base.change.apply(this,arguments) }, destroy:function(handler,remove){ if(!arguments.length){ this.$secret=null } return xP.controls._secret.base.destroy.apply(this,arguments) }, disable:function(disabled){ disabled=!arguments.length||disabled; if(this.disabled!==disabled){ if(disabled){ this.$secret.attr('disabled',true) }else{ this.$secret.removeAttr('disabled') } xP.controls._secret.base.disable.apply(this,arguments) } return this } }}); xP.controls.register({name:'password',base:'_secret',prototype:{ element_selector:'input[type=password]', init:function(params){ xP.controls.password.base.init.apply(this,arguments); var that=this; this.$secret.bind(this.change_events,function(){ that.$element.val(that.$secret.val()).change() }); this.control_button_view =$(this.control_button_view_html) .insertAfter(this.$secret) .click(function(){ if(that.disabled){ return false } that.$container.toggleClass( that.container_view_class ); that.control_button_view.toggleClass( that.control_button_view_class ); that.$element.toggle(); that.$secret.toggle(); ( that.$secret.is(':visible') ?that.$secret :that.$element ).focus()[0].selectionStart=1000 }) }, container_view_class:'alt', control_button_view_class:'control_button_password_view', control_button_view_html: '' }}); xP.controls.register({name:'number',base:'_secret',prototype:{ element_selector:'input.number,.number input', step:1, min:1-Number.MAX_VALUE, def:0, max:Number.MAX_VALUE-1, locale:xP.locale, init:function(params){ this.allow_chars_pattern=new RegExp( '^[-0-9' +this.locale.number.decimal +this.locale.number.grouping +']$' ); this.valid='[this].min<=[this]&&[this]<=[this].max'; xP.controls.number.base.init.apply(this,arguments); this.$element.wrap(this.element_wrap_html); var that=this; $(this.control_button_dec_html) .insertBefore(this.$element) .mousedown(function(){ if(!that.disabled){ that.dec() } return false }); $(this.control_button_inc_html) .insertAfter(this.$element) .mousedown(function(){ if(!that.disabled){ that.inc() } return false }); this.$element .val(this._format(this.$element.val())) .keydown(function(ev){ if(ev.which===38){ that.inc(); return false }else if(ev.which===40){ that.dec(); return false } }); this.$element.blur(function(){ that.val(that.val()) }) }, element_wrap_html:'', control_button_dec_html: '', control_button_inc_html: '', inc:function(){ var value=this.val(); if(!value&&value!==0){ this.val(value=this.def) } value=value-0+this.step*1; if(value>this.max*1){ return false }else if(valuethis.max*1){ value=this.max } return this.val(value) }, param:function(name,value){ if( (name==='min'&&this.val()value) ){ this.val(value) } if((name==='min'||name==='max')&&this.valid.process){ var result=xP.controls.number.base.param.apply( this,arguments ); this.valid.process(); return result } return xP.controls.number.base.param.apply( this,arguments ) }, val:function(value){ if(!arguments.length){ return this.disabled ?undefined :this._unformat(this.$element.val()) }else{ value=this._unformat(value); this.$secret.val(value); return xP.controls.number.base.val.apply( this, [this._format(value)] ) } }, _format:function(value){ var num=this.locale.number; value=(value+'').split('.'); return value[0].replace(num.format.grouping,'$1'+num.grouping) +(value[1] ?num.decimal+value[1] :'') }, _unformat:function(value){ var num=this.locale.number; return value!=='' ?((value+'') .replace(num.unformat.grouping,'') .replace(num.unformat.decimal,'.') .replace(/[^-.0-9]/g,'')*1) .toPrecision(15)*1 :'' } }}); xP.controls.register({name:'datemonth',base:'_field',prototype:{ element_selector:'input.datemonth,.datemonth input', locale:xP.locale, init:function(params){ xP.controls.datemonth.base.init.apply(this,arguments); this.$element.wrap(this.element_wrap_html); this.$element.hide(); this._.values=params.$element.val().split(this._split_pattern); if(this._.values.length<2){ this._.values=['','','','',''] } var html='', format=this.locale.date.split(this._split_pattern); for(var i=0,ii=format.length;i' }else if(format[i]=='mm'){ html+='' }else if(format[i]=='dd'){ if(this._month_name==='name'){ html+='', _month_name:'name', _split_pattern:/[-\s:.\/\\]/, _spliters:['-',''], _number_begin_html:'' +'' +this._number_begin_html+',min:0,max:59" value="' +(this._.values[4]!==undefined?this._.values[4]:'') +'" size="2" maxlength="2" class="minutes"/>'; var $time=$(html).insertBefore(this.$element),that=this; this._.pseudo.append(xP($time).each(function(){ this.change(function(){ that._change_pseudo() }) })); this._.$pseudo.add($time) } }}); xP.controls.register({name:'combobox',base:'string',prototype:{ element_selector:'.combobox input,input.combobox,input[list]', search_from_start:true, case_sensitive:false, init:function(params){ xP.controls.combobox.base.init.apply(this,arguments); var $list=$( "select#"+xP.taint_css(this.$element.attr('list')+'') ); if($list[0]){ $list.addClass('combolist'); var list=xP($list).first(), that=this; this.list=list; list.combobox=this; this.change(function(){ if(list._param('do_not_filter')){ return } var value=that.val(),i=0,ii=list._.options.length, options=list._.options; options.length=0; if(value!=''&&value!=undefined){ var mask=new RegExp( (that.search_from_start?'^':'') +xP.taint_css(value), that.case_sensitive?'':'i' ); list._.enabled_options.each(function(i){ if(this.text.match(mask)){ this.disabled=''; options[options.length]=this } }) }else{ list._.enabled_options.each(function(i){ this.disabled=''; options[options.length]=this }) } xP.after(function(){ var selected_index=list._.element.selectedIndex; list._.element.selectedIndex=-1; if(list._.options.length===0){ list.hide() }else if(value){ if(!that.case_sensitive){ value=value.toLowerCase() } var i=0,ii=list._.options.length; for(;irepeat.min}, from:repeat } } }}); xP.controls.register({name:'repeat_first_button',base:'button',prototype:{ element_selector:'.repeat_first_button', init:function(params){ xP.controls.repeat_first_button.base.init.apply(this,arguments); var parent=this.parent(),repeat=parent.repeat; if(!(repeat instanceof xP.repeats.item)){ return } this.click(function(){repeat.move(parent,0)}) .enabled={ on:function(){return 0parent._param('repeat_position')*1 }, from:repeat } } }}); xP.controls.register({name:'repeat_last_button',base:'button',prototype:{ element_selector:'.repeat_last_button', init:function(params){ xP.controls.repeat_first_button.base.init.apply(this,arguments); var parent=this.parent(),repeat=parent.repeat; if(!(repeat instanceof xP.repeats.item)){ return } this.click(function(){ repeat.move(parent,repeat.children().length-1) }).enabled={ on:function(){return repeat.children().length-1>parent._param('repeat_position')*1}, from:repeat } } }}); xP.repeats={ init:function(control){ if(control.repeat){ if($.type(control.repeat)!=='object'){ control.repeat={} } if(!control.root()._param('repeats')){ control.root()._param('repeats',{}) } control.repeat.id=control.repeat.id||control.name; var id=control.repeat.id, repeats=control.root()._param('repeats'); if(!repeats[id]){ repeats[id]=new xP.repeats.item(control) }else{ repeats[id].adopt(control) } } } }; xP.repeats.item=xP.register({name:'expromptum.repeats.item',base:xP.base,prototype:{ min:1, max:300, name_suffix_before:'[', name_suffix_after:']', id_suffix_before:'~', id_suffix_after:'', container_inited_class:'repeated', container_position_class:'repeated_', container_template_class:'repeated_template', init:function(control){ xP.debug( 'repeats','repeat', control.repeat.id,control.$element,this ); xP.repeats.item.base.init.apply(this); this.name_suffix_splitter=new RegExp( '(' +xP.taint_regexp(this.name_suffix_before) +'\\d+' +xP.taint_regexp(this.name_suffix_after) +')(?=(?:' +xP.taint_regexp(this.name_suffix_before) +'\\d+' +xP.taint_regexp(this.name_suffix_after) +')*$)' ); this.id_suffix_pattern=new RegExp( xP.taint_regexp(this.id_suffix_before) +'\\d+' +xP.taint_regexp(this.id_suffix_after) +'$' ); this.container_position_class_pattern=new RegExp( '(^|\\s)' +xP.taint_regexp(this.container_position_class) +'\\d+(?=\\s|$)' ); this._.children=[]; this.nesting=0; var parent=control; while(parent&&(parent=parent.parent())){ if(parent.repeat){ this.parent=parent; this.nesting=parent.repeat.nesting+1; break } } this.adopt(control,true); var that=this; xP.after(function(){ if(!that.template){ that.temp_template=true; var children=that.children(), control=children[children.length-1]; that.append(control); that.temp_template=false } },1) }, destroy:function(handler,remove){ xP.repeats.item.base.destroy.apply(this,arguments); if(!arguments.length&&this.control._){ this.control.root()._param('repeats')[this.id]=null } return this }, val:function(value){ return this.children().length }, children:function(){ return this._.children }, adopt:function(control,first){ control._param('repeat_position',0); var that=this, template=(control.repeat.template||this.temp_template) &&!this.template; $.extend(this,control.repeat); if(!this.control||template){ xP.after(function(){ that.control=control }); control.$container .find('*:not([id])').andSelf('*:not([id])').each(function(){ this.id='xP'+(Math.random()+'').substr(2,8) }); if(!control.html){ control.html=$('
') .append(control.$container.clone()) .html() } } xP.after(function(){ control.$container .find('*[id^=xP]').andSelf('*[id^=xP]').each(function(){ var $e=$(this), control=xP.controls.link($e); if(!control||control.$element[0]!==this){ $e.removeAttr('id') } }) }); if(template){ control._.repeat_template=true; control._.no_root_dependencies=true; repeat_change_suffixes( this, control, 888 ); control.$container.hide(); control.$container.addClass(this.container_template_class); xP.after(function(){ control.$container .find('input,textarea,select,button').andSelf() .attr('disabled',true) }) }else{ repeat_change_suffixes( this, control, this.position!==undefined ?this.position :this.children().length ); this.children().push(control) } if(this.control){ repeat_new_control_count++ } control.repeat=this; control.destroy(function(){ var children=that.children(),i=children.length; while(i--){ if(control===children[i]){ that._.children.splice(i,1); break } } if(!that.children().length){ that.destroy() } }); control.$container.addClass(this.container_inited_class) }, move:function(control,new_position){ var children=this.children(),i,ii, old_position=control._param('repeat_position'); if(new_positioni){ repeat_change_suffixes( this, children[ii], ii+1 ) } var id_suffix=this.id_suffix_before +repeat_new_control_count+this.id_suffix_after, $container=$( this.control._get_html().replace( /(\s(id|for|list)\s*=\s*([\"\'])?[^\s>]+)\3/g, '$1'+id_suffix+'$3' ) ); $container.find('[data-xp],[data-expromptum]') .removeAttr('data-xp').removeAttr('data-expromptum'); $container.find('[disabled]') .add($container.filter('[disabled]')) .removeAttr('disabled'); if(before){ $container.insertBefore(control.$container) }else{ $container.insertAfter(control.$container) } var result=repeat_init_new_control( this, $container, this.control, id_suffix, this.temp_template?888:i+1 ); var that=this; $container.find('input,textarea') .add($container.filter('input,textarea')) .not(function(){ var reset=xP(this).first().reset_on_repeat; return that.reset&&reset===false ||!that.reset&&!reset }) .removeAttr('checked') .not( '[type=button],[type=img],[type=submit],' +'[type=checkbox],[type=radio]' ) .val(''); if(!this.temp_template){ var c=this.children().pop(); this.children().splice(i+1,0,c) } this.change(); return result } }},'xP.repeats.item'); var repeat_init_new_control=function( repeat,$container,control,id_suffix,position ){ var id=control.$element.attr('id'); if(!id){ return } var selector='#' +xP.taint_css( id.replace( repeat.id_suffix_pattern,'' ) +id_suffix ), $element=$container.is(selector) ?$container :$(selector,$container); if(!$element[0]){ if(window.console){ console.warn( 'In',$container, 'not found',selector, 'by',control.$element.first(),'via suffix',id_suffix ) } return } var params=repeat_get_params( repeat, $container, control, id_suffix ); params.$element=$element; params.changed=undefined; if(control.repeat){ if(control.repeat.id!==repeat.id){ params.repeat={ id:control.repeat.id+id_suffix }; if( control===control.repeat.control &&!repeat.temp_template ){ params.repeat.template=true } }else{ control.repeat.position=position } } var result=xP.controls.link(params.$element); if(!result){ result=new xP.controls[params.type](params) } if(control.children){ control.children().each(function(){ repeat_init_new_control( repeat, $container, this, id_suffix, position ) }) } return result }, repeat_change_suffixes=function(repeat,control,position){ control._param('repeat_position',position); control.$container[0].className= control.$container[0].className.replace( repeat.container_position_class_pattern,'' ); if(!repeat.name_suffix_before){ return } control._.repeat_suffix =(repeat.parent&&repeat.parent._.repeat_suffix ?repeat.parent._.repeat_suffix:'') +repeat.name_suffix_before +position+repeat.name_suffix_after; control.$container.addClass( repeat.container_position_class+position ); var option_names={}, root_options=control.root()._param('_option'); control.$container.find('[name]').andSelf('[name]').each(function(){ var $e=$(this), name=$e.attr('name'), type=$e.attr('type'), parts=name.split(repeat.name_suffix_splitter), new_name=parts[0]+control._.repeat_suffix; for(var i=repeat.nesting*2+3;i