1 define(["jquery","underscore","Backbone"],function($,_
,Backbone
){var Form=function(){return Backbone
.View
.extend({hasFocus
:!1,initialize:function(options
){if(!Form
.templates
.form
)throw new Error("Templates not loaded");this.schema=function(){if(options
.schema
)return options
.schema
;var model
=options
.model
;if(!model
)throw new Error("Could not find schema");return _
.isFunction(model
.schema
)?model
.schema():model
.schema
}(),options
=_
.extend({template
:"form",fieldsetTemplate
:"fieldset",fieldTemplate
:"field"},options
);if(!options
.fieldsets
){var fields
=options
.fields
||_
.keys(this.schema
);options
.fieldsets
=[{fields
:fields
}]}this.options
=options
,this.model
=options
.model
,this.data
=options
.data
,this.fields
={}},render:function(){var self
=this,options
=this.options
,template
=Form
.templates
[options
.template
],$form
=$(template({fieldsets
:'<b class="bbf-tmp"></b>'})),$fieldsetContainer
=$(".bbf-tmp",$form
);return _
.each(options
.fieldsets
,function(fieldset
){$fieldsetContainer
.append(self
.renderFieldset(fieldset
))}),$fieldsetContainer
.children().unwrap(),this.setElement($form
),this.hasFocus
&&this.trigger("blur",this),this},renderFieldset:function(fieldset
){var self
=this,template
=Form
.templates
[this.options
.fieldsetTemplate
],schema
=this.schema
,getNested
=Form
.helpers
.getNested
;_
.isArray(fieldset
)&&(fieldset
={fields
:fieldset
});var $fieldset
=$(template(_
.extend({},fieldset
,{legend
:'<b class="bbf-tmp-legend"></b>',fields
:'<b class="bbf-tmp-fields"></b>'})));fieldset
.legend
?$fieldset
.find(".bbf-tmp-legend").replaceWith(fieldset
.legend
):$fieldset
.find(".bbf-tmp-legend").parent().remove();var $fieldsContainer
=$(".bbf-tmp-fields",$fieldset
);return _
.each(fieldset
.fields
,function(key
){var itemSchema=function(){if(schema
[key
])return schema
[key
];var path
=key
.replace(/\./g,".subSchema.");return getNested(schema,path)}();if(!itemSchema)throw"Field '"+key+"' not found in schema";var field=self.fields[key]=self.createField(key,itemSchema),fieldEl=field.render().el;field.editor.on("all",function(event){args=_.toArray(arguments),args[0]=key+":"+event,args.splice(1,0,this),this.trigger.apply(this,args)},self),field.editor.on("change",function(){this.trigger("change",self)},self),field.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},self),field.editor.on("blur",function(){if(!this.hasFocus)return;var self=this;setTimeout(function(){if(_.find(self.fields,function(field){return field.editor.hasFocus}))return;self.trigger("blur",self)},0)},self),itemSchema.type!="Hidden"&&$fieldsContainer.append(fieldEl)}),$fieldsContainer=$fieldsContainer.children().unwrap(),$fieldset},createField:function(key,schema){schema.template=schema.template||this.options.fieldTemplate;var options={form:this,key:key,schema:schema,idPrefix:this.options.idPrefix,template:this.options.fieldTemplate};return this.model?options.model=this.model:this.data?options.value=this.data[key]:options.value=null,new Form.Field(options)},validate:function(){var self=this,fields=this.fields,model=this.model,errors={};_.each(fields,function(field){var error=field.validate();error&&(errors[field.key]=error)});if(model&&model.validate){var modelErrors=model.validate(this.getValue());if(modelErrors){var isDictionary=_.isObject(modelErrors)&&!_.isArray(modelErrors);isDictionary||(errors._others=errors._others||[],errors._others.push(modelErrors)),isDictionary&&_.each(modelErrors,function(val,key){if(self.fields[key]&&!errors[key])self.fields[key].setError(val);else{errors._others=errors._others||[];var tmpErr={};tmpErr[key]=val,errors._others.push(tmpErr)}})}}return _.isEmpty(errors)?null:errors},commit:function(){var errors=this.validate();if(errors)return errors;var modelError;this.model.set(this.getValue(),{error:function(model,e){modelError=e}});if(modelError)return modelError},getValue:function(key){if(key)return this.fields[key].getValue();var values={};return _.each(this.fields,function(field){values[field.key]=field.getValue()}),values},setValue:function(data){for(var key in data)this.fields[key].setValue(data[key])},focus:function(){if(this.hasFocus)return;var fieldset=this.options.fieldsets[0];if(fieldset){var field;_.isArray(fieldset)?field=fieldset[0]:field=fieldset.fields[0],field&&this.fields[field].editor.focus()}},blur:function(){if(!this.hasFocus)return;focusedField=_.find(this.fields,function(field){return field.editor.hasFocus}),focusedField&&focusedField.editor.blur()},remove:function(){var fields=this.fields;for(var key in fields)fields[key].remove();Backbone.View.prototype.remove.call(this)},trigger:function(event){return event=="focus"?this.hasFocus=!0:event=="blur"&&(this.hasFocus=!1),Backbone.View.prototype.trigger.apply(this,arguments)}})}();return Form.helpers=function(){var helpers={};return helpers.getNested=function(obj,path){var fields=path.split("."),result=obj;for(var i=0,n=fields.length;i<n;i++)result=result[fields[i]];return result},helpers.keyToTitle=function(str){return str=str.replace(/([A
-Z
])/g," $1"),str=str.replace(/^./,function(str){return str.toUpperCase()}),str},helpers.compileTemplate=function(str){var _interpolateBackup=_.templateSettings.interpolate;_.templateSettings.interpolate=/\{\{(.+?)\}\}/g;var template=_.template(str);return _.templateSettings.interpolate=_interpolateBackup,template},helpers.createTemplate=function(str,context){var template=helpers.compileTemplate(str);return context?template(context):template},helpers.setTemplateCompiler=function(compiler){helpers.compileTemplate=compiler},helpers.setTemplates=function(templates,classNames){var createTemplate=helpers.createTemplate;Form.templates=Form.templates||{},Form.classNames=Form.classNames||{},_.each(templates,function(template,key,index){_.isString(template)&&(template=createTemplate(template)),Form.templates[key]=template}),_.extend(Form.classNames,classNames)},helpers.createEditor=function(schemaType,options){var constructorFn;return _.isString(schemaType)?constructorFn=Form.editors[schemaType]:constructorFn=schemaType,new constructorFn(options)},helpers.triggerCancellableEvent=function(subject,event,args,callback){if(!subject._callbacks||!subject._callbacks[event])return callback();var next=subject._callbacks[event].next;if(!next)return callback();var fn=next.callback,context=next.context||this;args.push(callback),fn.apply(context,args)},helpers.getValidator=function(validator){var validators=Form.validators;if(_.isRegExp(validator))return validators.regexp({regexp:validator});if(_.isString(validator)){if(!validators[validator])throw new Error('Validator "'+validator+'" not found');return validators[validator]()}if(_.isFunction(validator))return validator;if(_.isObject(validator)&&validator.type){var config=validator;return validators[config.type](config)}throw new Error("Invalid validator: "+validator)},helpers}(),Form.validators=function(){var validators={};return validators.errMessages={required:"Required",regexp:"Invalid",email:"Invalid email address",url:"Invalid URL",match:'Must match field "{{field}}"'},validators.required=function(options){return options=_.extend({type:"required",message:this.errMessages.required},options),function(value){options.value=value;var err={type:options.type,message:Form.helpers.createTemplate(options.message,options)};if(value===null||value===undefined||value==="")return err}},validators.regexp=function(options){if(!options.regexp)throw new Error('Missing required "regexp" option for "regexp" validator');return options=_.extend({type:"regexp",message:this.errMessages.regexp},options),function(value){options.value=value;var err={type:options.type,message:Form.helpers.createTemplate(options.message,options)};if(value===null||value===undefined||value==="")return;if(!options.regexp.test(value))return err}},validators.email=function(options){return options=_.extend({type:"email",message:this.errMessages.email,regexp:/^[\w
\-]{1,}([\w
\-\+.]{1,1}[\w
\-]{1,}){0,}[@][\w
\-]{1,}([.]([\w
\-]{1,})){1,3}$/},options),validators.regexp(options)},validators.url=function(options){return options=_.extend({type:"url",message:this.errMessages.url,regexp:/^(http
|https
):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i},options
),validators
.regexp(options
)},validators
.match=function(options
){if(!options
.field
)throw new Error('Missing required "field" options for "match" validator');return options
=_
.extend({type
:"match",message
:this.errMessages
.match
},options
),function(value
,attrs
){options
.value
=value
;var err
={type
:options
.type
,message
:Form
.helpers
.createTemplate(options
.message
,options
)};if(value
===null||value
===undefined||value
==="")return;if(value
!=attrs
[options
.field
])return err
}},validators
}(),Form
.Field=function(){var helpers
=Form
.helpers
,templates
=Form
.templates
;return Backbone
.View
.extend({initialize:function(options
){options
=options
||{},this.form
=options
.form
,this.key
=options
.key
,this.value
=options
.value
,this.model
=options
.model
,_
.isString(options
.schema
)&&(options
.schema
={type
:options
.schema
}),this.schema
=_
.extend({type
:"Text",title
:helpers
.keyToTitle(this.key
),template
:"field"},options
.schema
)},render:function(){var schema
=this.schema
,templates
=Form
.templates
,options
={form
:this.form
,key
:this.key
,schema
:schema
,idPrefix
:this.options
.idPrefix
,id
:this.getId()};this.model
?options
.model
=this.model
:options
.value
=this.value
;var editor
=this.editor
=helpers
.createEditor(schema
.type
,options
),$field
=$(templates
[schema
.template
]({key
:this.key
,title
:schema
.title
,id
:editor
.id
,type
:schema
.type
,editor
:'<b class="bbf-tmp-editor"></b>',help
:'<b class="bbf-tmp-help"></b>'}));return $field
.find(".bbf-tmp-editor").replaceWith(editor
.render().el
),this.$help
=$(".bbf-tmp-help",$field
).parent(),this.$help
.empty(),this.schema
.help
&&this.$help
.html(this.schema
.help
),this.schema
.fieldClass
&&$field
.addClass(this.schema
.fieldClass
),this.schema
.fieldAttrs
&&$field
.attr(this.schema
.fieldAttrs
),this.setElement($field
),this},getId:function(){var prefix
=this.options
.idPrefix
,id
=this.key
;return id
=id
.replace(/\./g,"_"),_
.isString(prefix
)||_
.isNumber(prefix
)?prefix
+id
:_
.isNull(prefix
)?id
:this.model
?this.model
.cid
+"_"+id
:id
},validate:function(){var error
=this.editor
.validate();return error
?this.setError(error
.message
):this.clearError(),error
},setError:function(msg
){if(this.editor
.hasNestedForm
)return;var errClass
=Form
.classNames
.error
;this.$el
.addClass(errClass
),this.$help
&&this.$help
.html(msg
)},clearError:function(){var errClass
=Form
.classNames
.error
;this.$el
.removeClass(errClass
);if(this.$help
){this.$help
.empty();var helpMsg
=this.schema
.help
;helpMsg
&&this.$help
.html(helpMsg
)}},commit:function(){return this.editor
.commit()},getValue:function(){return this.editor
.getValue()},setValue:function(value
){this.editor
.setValue(value
)},focus:function(){this.editor
.focus()},blur:function(){this.editor
.blur()},remove:function(){this.editor
.remove(),Backbone
.View
.prototype.remove
.call(this)}})}(),Form
.editors=function(){var helpers
=Form
.helpers
,editors
={};return editors
.Base
=Backbone
.View
.extend({defaultValue
:null,hasFocus
:!1,initialize:function(options
){var options
=options
||{};if(options
.model
){if(!options
.key
)throw"Missing option: 'key'";this.model
=options
.model
,this.value
=this.model
.get(options
.key
)}else options
.value
&&(this.value
=options
.value
);this.value
===undefined&&(this.value
=this.defaultValue
),this.key
=options
.key
,this.form
=options
.form
,this.schema
=options
.schema
||{},this.validators
=options
.validators
||this.schema
.validators
,this.$el
.attr("name",this.getName()),this.schema
.editorClass
&&this.$el
.addClass(this.schema
.editorClass
),this.schema
.editorAttrs
&&this.$el
.attr(this.schema
.editorAttrs
)},getValue:function(){throw"Not implemented. Extend and override this method."},setValue:function(){throw"Not implemented. Extend and override this method."},focus:function(){throw"Not implemented. Extend and override this method."},blur:function(){throw"Not implemented. Extend and override this method."},getName:function(){var key
=this.key
||"";return key
.replace(/\./g,"_")},commit:function(){var error
=this.validate();if(error
)return error
;this.model
.set(this.key
,this.getValue(),{error:function(model
,e
){error
=e
}});if(error
)return error
},validate:function(){var $el
=this.$el
,error
=null,value
=this.getValue(),formValues
=this.form
?this.form
.getValue():{},validators
=this.validators
,getValidator
=Form
.helpers
.getValidator
;return validators
&&_
.every(validators
,function(validator
){return error
=getValidator(validator
)(value
,formValues
),continueLoop
=error
?!1:!0}),error
},trigger:function(event
){return event
=="focus"?this.hasFocus
=!0:event
=="blur"&&(this.hasFocus
=!1),Backbone
.View
.prototype.trigger
.apply(this,arguments
)}}),editors
.Text
=editors
.Base
.extend({tagName
:"input",defaultValue
:"",previousValue
:"",events
:{keyup
:"determineChange",keypress:function(event
){var self
=this;setTimeout(function(){self
.determineChange()},0)},select:function(event
){this.trigger("select",this)},focus:function(event
){this.trigger("focus",this)},blur:function(event
){this.trigger("blur",this)}},initialize:function(options
){editors
.Base
.prototype.initialize
.call(this,options
);var schema
=this.schema
,type
="text";schema
&&schema
.editorAttrs
&&schema
.editorAttrs
.type
&&(type
=schema
.editorAttrs
.type
),schema
&&schema
.dataType
&&(type
=schema
.dataType
),this.$el
.attr("type",type
)},render:function(){return this.setValue(this.value
),this},determineChange:function(event
){var currentValue
=this.$el
.val(),changed
=currentValue
!=this.previousValue
;changed
&&(this.previousValue
=currentValue
,this.trigger("change",this))},getValue:function(){return this.$el
.val()},setValue:function(value
){this.$el
.val(value
)},focus:function(){if(this.hasFocus
)return;this.$el
.focus()},blur:function(){if(!this.hasFocus
)return;this.$el
.blur()},select:function(){this.$el
.select()}}),editors
.Number
=editors
.Text
.extend({defaultValue
:0,events
:_
.extend({},editors
.Text
.prototype.events
,{keypress
:"onKeyPress"}),initialize:function(options
){editors
.Text
.prototype.initialize
.call(this,options
),this.$el
.attr("type","number")},onKeyPress:function(event
){var self
=this,delayedDetermineChange=function(){setTimeout(function(){self
.determineChange()},0)};if(event
.charCode
==0){delayedDetermineChange();return}var newVal
=this.$el
.val()+String
.fromCharCode(event
.charCode
),numeric
=/^[0-9]*\.?[0-9]*?$/.test(newVal
);numeric
?delayedDetermineChange():event
.preventDefault()},getValue:function(){var value
=this.$el
.val();return value
===""?null:parseFloat(value
,10)},setValue:function(value
){value=function(){return _
.isNumber(value
)?value
:_
.isString(value
)&&value
!==""?parseFloat(value
,10):null}(),_
.isNaN(value
)&&(value
=null),editors
.Text
.prototype.setValue
.call(this,value
)}}),editors
.Password
=editors
.Text
.extend({initialize:function(options
){editors
.Text
.prototype.initialize
.call(this,options
),this.$el
.attr("type","password")}}),editors
.TextArea
=editors
.Text
.extend({tagName
:"textarea"}),editors
.Checkbox
=editors
.Base
.extend({defaultValue
:!1,tagName
:"input",events
:{click:function(event
){this.trigger("change",this)},focus:function(event
){this.trigger("focus",this)},blur:function(event
){this.trigger("blur",this)}},initialize:function(options
){editors
.Base
.prototype.initialize
.call(this,options
),this.$el
.attr("type","checkbox")},render:function(){return this.setValue(this.value
),this},getValue:function(){return this.$el
.prop("checked")},setValue:function(value
){value
&&this.$el
.prop("checked",!0)},focus:function(){if(this.hasFocus
)return;this.$el
.focus()},blur:function(){if(!this.hasFocus
)return;this.$el
.blur()}}),editors
.Hidden
=editors
.Base
.extend({defaultValue
:"",initialize:function(options
){editors
.Text
.prototype.initialize
.call(this,options
),this.$el
.attr("type","hidden")},getValue:function(){return this.value
},setValue:function(value
){this.value
=value
},focus:function(){},blur:function(){}}),editors
.Select
=editors
.Base
.extend({tagName
:"select",events
:{change:function(event
){this.trigger("change",this)},focus:function(event
){this.trigger("focus",this)},blur:function(event
){this.trigger("blur",this)}},initialize:function(options
){editors
.Base
.prototype.initialize
.call(this,options
);if(!this.schema
||!this.schema
.options
)throw"Missing required 'schema.options'"},render:function(){var options
=this.schema
.options
,self
=this;if(options
instanceof Backbone
.Collection
){var collection
=options
;collection
.length
>0?this.renderOptions(options
):collection
.fetch({success:function(collection
){self
.renderOptions(options
)}})}else _
.isFunction(options
)?options(function(result
){self
.renderOptions(result
)}):this.renderOptions(options
);return this},renderOptions:function(options
){var $select
=this.$el
,html
;_
.isString(options
)?html
=options
:_
.isArray(options
)?html
=this._arrayToHtml(options
):options
instanceof Backbone
.Collection
&&(html
=this._collectionToHtml(options
)),$select
.html(html
),this.setValue(this.value
)},getValue:function(){return this.$el
.val()},setValue:function(value
){this.$el
.val(value
)},focus:function(){if(this.hasFocus
)return;this.$el
.focus()},blur:function(){if(!this.hasFocus
)return;this.$el
.blur()},_collectionToHtml:function(collection
){var array
=[];collection
.each(function(model
){array
.push({val
:model
.id
,label
:model
.toString()})});var html
=this._arrayToHtml(array
);return html
},_arrayToHtml:function(array
){var html
=[];return _
.each(array
,function(option
){if(_
.isObject(option
)){var val
=option
.val
?option
.val
:"";html
.push('<option value="'+val
+'">'+option
.label
+"</option>")}else html
.push("<option>"+option
+"</option>")}),html
.join("")}}),editors
.Radio
=editors
.Select
.extend({tagName
:"ul",className
:"bbf-radio",events
:{"click input[type=radio]:not(:checked)":function(){this.trigger("change",this)},"focus input[type=radio]":function(){if(this.hasFocus
)return;this.trigger("focus",this)},"blur input[type=radio]":function(){if(!this.hasFocus
)return;var self
=this;setTimeout(function(){if(self
.$("input[type=radio]:focus")[0])return;self
.trigger("blur",self
)},0)}},getValue:function(){return this.$("input[type=radio]:checked").val()},setValue:function(value
){this.$("input[type=radio]").val([value
])},focus:function(){if(this.hasFocus
)return;var checked
=this.$("input[type=radio]:checked");if(checked
[0]){checked
.focus();return}this.$("input[type=radio]").first().focus()},blur:function(){if(!this.hasFocus
)return;this.$("input[type=radio]:focus").blur()},_arrayToHtml:function(array
){var html
=[],self
=this;return _
.each(array
,function(option
,index
){var itemHtml
="<li>";if(_
.isObject(option
)){var val
=option
.val
?option
.val
:"";itemHtml
+='<input type="radio" name="'+self
.id
+'" value="'+val
+'" id="'+self
.id
+"-"+index
+'" />',itemHtml
+='<label for="'+self
.id
+"-"+index
+'">'+option
.label
+"</label>"}else itemHtml
+='<input type="radio" name="'+self
.id
+'" value="'+option
+'" id="'+self
.id
+"-"+index
+'" />',itemHtml
+='<label for="'+self
.id
+"-"+index
+'">'+option
+"</label>";itemHtml
+="</li>",html
.push(itemHtml
)}),html
.join("")}}),editors
.Checkboxes
=editors
.Select
.extend({tagName
:"ul",className
:"bbf-checkboxes",events
:{"click input[type=checkbox]":function(){this.trigger("change",this)},"focus input[type=checkbox]":function(){if(this.hasFocus
)return;this.trigger("focus",this)},"blur input[type=checkbox]":function(){if(!this.hasFocus
)return;var self
=this;setTimeout(function(){if(self
.$("input[type=checkbox]:focus")[0])return;self
.trigger("blur",self
)},0)}},getValue:function(){var values
=[];return this.$("input[type=checkbox]:checked").each(function(){values
.push($(this).val())}),values
},setValue:function(values
){_
.isArray(values
)||(values
=[values
]),this.$("input[type=checkbox]").val(values
)},focus:function(){if(this.hasFocus
)return;this.$("input[type=checkbox]").first().focus()},blur:function(){if(!this.hasFocus
)return;this.$("input[type=checkbox]:focus").blur()},_arrayToHtml:function(array
){var html
=[],self
=this;return _
.each(array
,function(option
,index
){var itemHtml
="<li>";if(_
.isObject(option
)){var val
=option
.val
?option
.val
:"";itemHtml
+='<input type="checkbox" name="'+self
.id
+'" value="'+val
+'" id="'+self
.id
+"-"+index
+'" />',itemHtml
+='<label for="'+self
.id
+"-"+index
+'">'+option
.label
+"</label>"}else itemHtml
+='<input type="checkbox" name="'+self
.id
+'" value="'+option
+'" id="'+self
.id
+"-"+index
+'" />',itemHtml
+='<label for="'+self
.id
+"-"+index
+'">'+option
+"</label>";itemHtml
+="</li>",html
.push(itemHtml
)}),html
.join("")}}),editors
.Object
=editors
.Base
.extend({hasNestedForm
:!0,className
:"bbf-object",initialize:function(options
){this.value
={},editors
.Base
.prototype.initialize
.call(this,options
);if(!this.schema
.subSchema
)throw new Error("Missing required 'schema.subSchema' option for Object editor")},render:function(){return this.form
=new Form({schema
:this.schema
.subSchema
,data
:this.value
,idPrefix
:this.id
+"_",fieldTemplate
:"nestedField"}),this._observeFormEvents(),this.$el
.html(this.form
.render().el
),this.hasFocus
&&this.trigger("blur",this),this},getValue:function(){return this.form
?this.form
.getValue():this.value
},setValue:function(value
){this.value
=value
,this.render()},focus:function(){if(this.hasFocus
)return;this.form
.focus()},blur:function(){if(!this.hasFocus
)return;this.form
.blur()},remove:function(){this.form
.remove(),Backbone
.View
.prototype.remove
.call(this)},validate:function(){return this.form
.validate()},_observeFormEvents:function(){this.form
.on("all",function(){args
=_
.toArray(arguments
),args
[1]=this,this.trigger
.apply(this,args
)},this)}}),editors
.NestedModel
=editors
.Object
.extend({initialize:function(options
){editors
.Base
.prototype.initialize
.call(this,options
);if(!options
.schema
.model
)throw'Missing required "schema.model" option for NestedModel editor'},render:function(){var data
=this.value
||{},key
=this.key
,nestedModel
=this.schema
.model
,nestedModelSchema
=nestedModel
.prototype.schema
;return _
.isFunction(nestedModelSchema
)&&(nestedModelSchema
=nestedModelSchema()),this.form
=new Form({schema
:nestedModelSchema
,model
:new nestedModel(data
),idPrefix
:this.id
+"_",fieldTemplate
:"nestedField"}),this._observeFormEvents(),this.$el
.html(this.form
.render().el
),this.hasFocus
&&this.trigger("blur",this),this},commit:function(){var error
=this.form
.commit();return error
?(this.$el
.addClass("error"),error
):editors
.Object
.prototype.commit
.call(this)}}),editors
.Date
=editors
.Base
.extend({events
:{"change select":function(){this.updateHidden(),this.trigger("change",this)},"focus select":function(){if(this.hasFocus
)return;this.trigger("focus",this)},"blur select":function(){if(!this.hasFocus
)return;var self
=this;setTimeout(function(){if(self
.$("select:focus")[0])return;self
.trigger("blur",self
)},0)}},initialize:function(options
){options
=options
||{},editors
.Base
.prototype.initialize
.call(this,options
);var Self
=editors
.Date
,today
=new Date
;this.options
=_
.extend({monthNames
:Self
.monthNames
,showMonthNames
:Self
.showMonthNames
},options
),this.schema
=_
.extend({yearStart
:today
.getFullYear()-100,yearEnd
:today
.getFullYear()},options
.schema
||{}),this.value
&&!_
.isDate(this.value
)&&(this.value
=new Date(this.value
));if(!this.value
){var date
=new Date
;date
.setSeconds(0),date
.setMilliseconds(0),this.value
=date
}},render:function(){var options
=this.options
,schema
=this.schema
,datesOptions
=_
.map(_
.range(1,32),function(date
){return'<option value="'+date
+'">'+date
+"</option>"}),monthsOptions
=_
.map(_
.range(0,12),function(month
){var value
=options
.showMonthNames
?options
.monthNames
[month
]:month
+1;return'<option value="'+month
+'">'+value
+"</option>"}),yearsOptions
=_
.map(_
.range(schema
.yearStart
,schema
.yearEnd
+1),function(year
){return'<option value="'+year
+'">'+year
+"</option>"}),$el
=$(Form
.templates
.date({dates
:datesOptions
.join(""),months
:monthsOptions
.join(""),years
:yearsOptions
.join("")}));return this.$date
=$el
.find('select[data-type="date"]'),this.$month
=$el
.find('select[data-type="month"]'),this.$year
=$el
.find('select[data-type="year"]'),this.$hidden
=$('<input type="hidden" name="'+this.key
+'" />'),$el
.append(this.$hidden
),this.setValue(this.value
),this.setElement($el
),this.$el
.attr("id",this.id
),this.hasFocus
&&this.trigger("blur",this),this},getValue:function(){var year
=this.$year
.val(),month
=this.$month
.val(),date
=this.$date
.val();return!year
||!month
||!date
?null:new Date(year
,month
,date
)},setValue:function(date
){this.$date
.val(date
.getDate()),this.$month
.val(date
.getMonth()),this.$year
.val(date
.getFullYear()),this.updateHidden()},focus:function(){if(this.hasFocus
)return;this.$("select").first().focus()},blur:function(){if(!this.hasFocus
)return;this.$("select:focus").blur()},updateHidden:function(){var val
=this.getValue();_
.isDate(val
)&&(val
=val
.toISOString()),this.$hidden
.val(val
)}},{showMonthNames
:!0,monthNames
:["January","February","March","April","May","June","July","August","September","October","November","December"]}),editors
.DateTime
=editors
.Base
.extend({events
:{"change select":function(){this.updateHidden(),this.trigger("change",this)},"focus select":function(){if(this.hasFocus
)return;this.trigger("focus",this)},"blur select":function(){if(!this.hasFocus
)return;var self
=this;setTimeout(function(){if(self
.$("select:focus")[0])return;self
.trigger("blur",self
)},0)}},initialize:function(options
){options
=options
||{},editors
.Base
.prototype.initialize
.call(this,options
),this.options
=_
.extend({DateEditor
:editors
.DateTime
.DateEditor
},options
),this.schema
=_
.extend({minsInterval
:15},options
.schema
||{}),this.dateEditor
=new this.options
.DateEditor(options
),this.value
=this.dateEditor
.value
},render:function(){function pad(n
){return n
<10?"0"+n
:n
}var schema
=this.schema
,hoursOptions
=_
.map(_
.range(0,24),function(hour
){return'<option value="'+hour
+'">'+pad(hour
)+"</option>"}),minsOptions
=_
.map(_
.range(0,60,schema
.minsInterval
),function(min
){return'<option value="'+min
+'">'+pad(min
)+"</option>"}),$el
=$(Form
.templates
.dateTime({date
:'<b class="bbf-tmp"></b>',hours
:hoursOptions
.join(),mins
:minsOptions
.join()}));return $el
.find(".bbf-tmp").replaceWith(this.dateEditor
.render().el
),this.$hour
=$el
.find('select[data-type="hour"]'),this.$min
=$el
.find('select[data-type="min"]'),this.$hidden
=$el
.find('input[type="hidden"]'),this.setValue(this.value
),this.setElement($el
),this.$el
.attr("id",this.id
),this.hasFocus
&&this.trigger("blur",this),this},getValue:function(){var date
=this.dateEditor
.getValue(),hour
=this.$hour
.val(),min
=this.$min
.val();return!date
||!hour
||!min
?null:(date
.setHours(hour
),date
.setMinutes(min
),date
)},setValue:function(date
){_
.isDate(date
)||(date
=new Date(date
)),this.dateEditor
.setValue(date
),this.$hour
.val(date
.getHours()),this.$min
.val(date
.getMinutes()),this.updateHidden()},focus:function(){if(this.hasFocus
)return;this.$("select").first().focus()},blur:function(){if(!this.hasFocus
)return;this.$("select:focus").blur()},updateHidden:function(){var val
=this.getValue();_
.isDate(val
)&&(val
=val
.toISOString()),this.$hidden
.val(val
)},remove:function(){this.dateEditor
.remove(),editors
.Base
.prototype.remove
.call(this)}},{DateEditor
:editors
.Date
}),editors
}(),Form
.setTemplates
=Form
.helpers
.setTemplates
,Form
.setTemplateCompiler
=Form
.helpers
.setTemplateCompiler
,Form
.templates
={},Form
.setTemplates({form
:' <form class="bbf-form">{{fieldsets}}</form> ',fieldset
:" <fieldset> <legend>{{legend}}</legend> <ul>{{fields}}</ul> </fieldset> ",field
:' <li class="bbf-field field-{{key}}"> <label for="{{id}}">{{title}}</label> <div class="bbf-editor">{{editor}}</div> <div class="bbf-help">{{help}}</div> </li> ',nestedField
:' <li class="bbf-field bbf-nested-field field-{{key}}" title="{{title}}"> <label for="{{id}}">{{title}}</label> <div class="bbf-editor">{{editor}}</div> <div class="bbf-help">{{help}}</div> </li> ',list
:' <div class="bbf-list"> <ul>{{items}}</ul> <div class="bbf-actions"><button type="button" data-action="add">Add</div> </div> ',listItem
:' <li> <button type="button" data-action="remove" class="bbf-remove">×</button> <div class="bbf-editor-container">{{editor}}</div> </li> ',date
:' <div class="bbf-date"> <select data-type="date" class="bbf-date">{{dates}}</select> <select data-type="month" class="bbf-month">{{months}}</select> <select data-type="year" class="bbf-year">{{years}}</select> </div> ',dateTime
:' <div class="bbf-datetime"> <div class="bbf-date-container">{{date}}</div> <select data-type="hour">{{hours}}</select> : <select data-type="min">{{mins}}</select> </div> ',"list.Modal":' <div class="bbf-list-modal"> {{summary}} </div> '},{error
:"bbf-error"}),Form
})