text: /**
  
  * Combodate - 1.0.4
  
  * Dropdown date and time picker.
  
  * Converts text input into dropdowns to pick day, month, year, hour, minute and second.
  
  * Uses momentjs as datetime library http://momentjs.com.
  
  * For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang 
  
  *
  
  * Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
  
  * In combodate: 
  
  * 12:00 pm --> 12:00 (24-h format, midday)
  
  * 12:00 am --> 00:00 (24-h format, midnight, start of day)
  
  * 
  
  * Differs from momentjs parse rules:
  
  * 00:00 pm, 12:00 pm --> 12:00 (24-h format, day not change)
  
  * 00:00 am, 12:00 am --> 00:00 (24-h format, day not change)
  
  * 
  
  * 
  
  * Author: Vitaliy Potapov
  
  * Project page: http://github.com/vitalets/combodate
  
  * Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
  
  **/
  
  (function ($) {
  
  
  
      var Combodate = function (element, options) {
  
          this.$element = $(element);
  
          if(!this.$element.is('input')) {
  
              $.error('Combodate should be applied to INPUT element');
  
              return;
  
          }
  
          this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
  
          this.init();  
  
       };
  
  
  
      Combodate.prototype = {
  
          constructor: Combodate, 
  
          init: function () {
  
              this.map = {
  
                  //key   regexp    moment.method
  
                  day:    ['D',    'date'], 
  
                  month:  ['M',    'month'], 
  
                  year:   ['Y',    'year'], 
  
                  hour:   ['[Hh]', 'hours'],
  
                  minute: ['m',    'minutes'], 
  
                  second: ['s',    'seconds'],
  
                  ampm:   ['[Aa]', ''] 
  
              };
  
              
  
              this.$widget = $('<span class="combodate"></span>').html(this.getTemplate());
  
                        
  
              this.initCombos();
  
              
  
              //update original input on change 
  
              this.$widget.on('change', 'select', $.proxy(function(){
  
                  this.$element.val(this.getValue());
  
              }, this));
  
              
  
              this.$widget.find('select').css('width', 'auto');
  
                                         
  
              //hide original input and insert widget                                       
  
              this.$element.hide().after(this.$widget);
  
              
  
              //set initial value
  
              this.setValue(this.$element.val() || this.options.value);
  
          },
  
          
  
          /*
  
           Replace tokens in template with <select> elements 
  
          */         
  
          getTemplate: function() {
  
              var tpl = this.options.template;
  
  
  
              //first pass
  
              $.each(this.map, function(k, v) {
  
                  v = v[0]; 
  
                  var r = new RegExp(v+'+'),
  
                      token = v.length > 1 ? v.substring(1, 2) : v;
  
                      
  
                  tpl = tpl.replace(r, '{'+token+'}');
  
              });
  
  
  
              //replace spaces with &nbsp;
  
              tpl = tpl.replace(/ /g, '&nbsp;');
  
  
  
              //second pass
  
              $.each(this.map, function(k, v) {
  
                  v = v[0];
  
                  var token = v.length > 1 ? v.substring(1, 2) : v;
  
                      
  
                  tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
  
              });   
  
  
  
              return tpl;
  
          },
  
          
  
          /*
  
           Initialize combos that presents in template 
  
          */        
  
          initCombos: function() {
  
              var that = this;
  
              $.each(this.map, function(k, v) {
  
                 var $c = that.$widget.find('.'+k), f, items;
  
                 if($c.length) {
  
                     that['$'+k] = $c; //set properties like this.$day, this.$month etc.
  
                     f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); //define method name to fill items, e.g `fillDays`
  
                     items = that[f](); 
  
                     that['$'+k].html(that.renderItems(items));
  
                 }
  
              }); 
  
          },
  
          
  
          /*
  
           Initialize items of combos. Handles `firstItem` option 
  
          */
  
          initItems: function(key) {
  
              var values = [],
  
                  relTime;
  
                  
  
              if(this.options.firstItem === 'name') {
  
                  //need both to support moment ver < 2 and  >= 2
  
                  relTime = moment.relativeTime || moment.langData()._relativeTime; 
  
                  var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key];
  
                  //take last entry (see momentjs lang files structure) 
  
                  header = header.split(' ').reverse()[0];                
  
                  values.push(['', header]);
  
              } else if(this.options.firstItem === 'empty') {
  
                  values.push(['', '']);
  
              }
  
              return values;
  
          },        
  
          
  
          /*
  
          render items to string of <option> tags
  
          */
  
          renderItems: function(items) {
  
              var str = [];
  
              for(var i=0; i<items.length; i++) {
  
                  str.push('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');                
  
              }
  
              return str.join("\n");
  
          },        
  
  
  
          /*
  
          fill day
  
          */
  
          fillDay: function() {
  
              var items = this.initItems('d'), name, i,
  
                  twoDigit = this.options.template.indexOf('DD') !== -1;
  
                  
  
              for(i=1; i<=31; i++) {
  
                  name = twoDigit ? this.leadZero(i) : i;
  
                  items.push([i, name]);
  
              }
  
              return items;        
  
          },
  
          
  
          /*
  
          fill month
  
          */
  
          fillMonth: function() {
  
              var items = this.initItems('M'), name, i, 
  
                  longNames = this.options.template.indexOf('MMMM') !== -1,
  
                  shortNames = this.options.template.indexOf('MMM') !== -1,
  
                  twoDigit = this.options.template.indexOf('MM') !== -1;
  
                  
  
              for(i=0; i<=11; i++) {
  
                  if(longNames) {
  
                      //see https://github.com/timrwood/momentjs.com/pull/36
  
                      name = moment().date(1).month(i).format('MMMM');
  
                  } else if(shortNames) {
  
                      name = moment().date(1).month(i).format('MMM');
  
                  } else if(twoDigit) {
  
                      name = this.leadZero(i+1);
  
                  } else {
  
                      name = i+1;
  
                  }
  
                  items.push([i, name]);
  
              } 
  
              return items;
  
          },  
  
          
  
          /*
  
          fill year
  
          */
  
          fillYear: function() {
  
              var items = [], name, i, 
  
                  longNames = this.options.template.indexOf('YYYY') !== -1;
  
             
  
              for(i=this.options.maxYear; i>=this.options.minYear; i--) {
  
                  name = longNames ? i : (i+'').substring(2);
  
                  items[this.options.yearDescending ? 'push' : 'unshift']([i, name]);
  
              }
  
              
  
              items = this.initItems('y').concat(items);
  
              
  
              return items;              
  
          },    
  
          
  
          /*
  
          fill hour
  
          */
  
          fillHour: function() {
  
              var items = this.initItems('h'), name, i,
  
                  h12 = this.options.template.indexOf('h') !== -1,
  
                  h24 = this.options.template.indexOf('H') !== -1,
  
                  twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
  
                  min = h12 ? 1 : 0, 
  
                  max = h12 ? 12 : 23;
  
                  
  
              for(i=min; i<=max; i++) {
  
                  name = twoDigit ? this.leadZero(i) : i;
  
                  items.push([i, name]);
  
              } 
  
              return items;                 
  
          },    
  
          
  
          /*
  
          fill minute
  
          */
  
          fillMinute: function() {
  
              var items = this.initItems('m'), name, i,
  
                  twoDigit = this.options.template.indexOf('mm') !== -1;
  
  
  
              for(i=0; i<=59; i+= this.options.minuteStep) {
  
                  name = twoDigit ? this.leadZero(i) : i;
  
                  items.push([i, name]);
  
              }    
  
              return items;              
  
          },  
  
          
  
          /*
  
          fill second
  
          */
  
          fillSecond: function() {
  
              var items = this.initItems('s'), name, i,
  
                  twoDigit = this.options.template.indexOf('ss') !== -1;
  
  
  
              for(i=0; i<=59; i+= this.options.secondStep) {
  
                  name = twoDigit ? this.leadZero(i) : i;
  
                  items.push([i, name]);
  
              }    
  
              return items;              
  
          },  
  
          
  
          /*
  
          fill ampm
  
          */
  
          fillAmpm: function() {
  
              var ampmL = this.options.template.indexOf('a') !== -1,
  
                  ampmU = this.options.template.indexOf('A') !== -1,            
  
                  items = [
  
                      ['am', ampmL ? 'am' : 'AM'],
  
                      ['pm', ampmL ? 'pm' : 'PM']
  
                  ];
  
              return items;                              
  
          },                                       
  
          
  
          /*
  
           Returns current date value from combos. 
  
           If format not specified - `options.format` used.
  
           If format = `null` - Moment object returned.
  
          */
  
          getValue: function(format) {
  
              var dt, values = {}, 
  
                  that = this,
  
                  notSelected = false;
  
                  
  
              //getting selected values    
  
              $.each(this.map, function(k, v) {
  
                  if(k === 'ampm') {
  
                      return;
  
                  }
  
                  var def = k === 'day' ? 1 : 0;
  
                    
  
                  values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def; 
  
                  
  
                  if(isNaN(values[k])) {
  
                     notSelected = true;
  
                     return false; 
  
                  }
  
              });
  
              
  
              //if at least one visible combo not selected - return empty string
  
              if(notSelected) {
  
                 return '';
  
              }
  
              
  
              //convert hours 12h --> 24h 
  
              if(this.$ampm) {
  
                  //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
  
                  if(values.hour === 12) {
  
                      values.hour = this.$ampm.val() === 'am' ? 0 : 12;                    
  
                  } else {
  
                      values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
  
                  }
  
              }    
  
              
  
              dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
  
              
  
              //highlight invalid date
  
              this.highlight(dt);
  
                                
  
              format = format === undefined ? this.options.format : format;
  
              if(format === null) {
  
                 return dt.isValid() ? dt : null; 
  
              } else {
  
                 return dt.isValid() ? dt.format(format) : ''; 
  
              }           
  
          },
  
          
  
          setValue: function(value) {
  
              if(!value) {
  
                  return;
  
              }
  
              
  
              var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
  
                  that = this,
  
                  values = {};
  
              
  
                  //function to find nearest value in select options
  
                  function getNearest($select, value) {
  
                      var delta = {};
  
                      $select.children('option').each(function(i, opt){
  
                          var optValue = $(opt).attr('value'),
  
                          distance;
  
  
  
                          if(optValue === '') return;
  
                          distance = Math.abs(optValue - value); 
  
                          if(typeof delta.distance === 'undefined' || distance < delta.distance) {
  
                              delta = {value: optValue, distance: distance};
  
                          } 
  
                      }); 
  
                      return delta.value;
  
                  }             
  
              
  
              if(dt.isValid()) {
  
                   //read values from date object
  
                   $.each(this.map, function(k, v) {
  
                       if(k === 'ampm') {
  
                           return; 
  
                       }
  
                       values[k] = dt[v[1]]();
  
                   });
  
                 
  
                 if(this.$ampm) {
  
                     //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
  
                     if(values.hour >= 12) {
  
                         values.ampm = 'pm';
  
                         if(values.hour > 12) {
  
                             values.hour -= 12;
  
                         }
  
                     } else {
  
                         values.ampm = 'am';
  
                         if(values.hour === 0) {
  
                             values.hour = 12;
  
                         }
  
                     } 
  
                 }
  
                 
  
                 $.each(values, function(k, v) {
  
                     //call val() for each existing combo, e.g. this.$hour.val()
  
                     if(that['$'+k]) {
  
                         
  
                         if(k === 'minute' && that.options.minuteStep > 1 && that.options.roundTime) {
  
                            v = getNearest(that['$'+k], v);
  
                         }
  
                         
  
                         if(k === 'second' && that.options.secondStep > 1 && that.options.roundTime) {
  
                            v = getNearest(that['$'+k], v);
  
                         }                       
  
                         
  
                         that['$'+k].val(v);                       
  
                     }
  
                 });
  
                 
  
                 this.$element.val(dt.format(this.options.format));
  
              }
  
          },
  
          
  
          /*
  
           highlight combos if date is invalid
  
          */
  
          highlight: function(dt) {
  
              if(!dt.isValid()) {
  
                  if(this.options.errorClass) {
  
                      this.$widget.addClass(this.options.errorClass);
  
                  } else {
  
                      //store original border color
  
                      if(!this.borderColor) {
  
                          this.borderColor = this.$widget.find('select').css('border-color'); 
  
                      }
  
                      this.$widget.find('select').css('border-color', 'red');
  
                  } 
  
              } else {
  
                  if(this.options.errorClass) {
  
                      this.$widget.removeClass(this.options.errorClass);
  
                  } else {
  
                      this.$widget.find('select').css('border-color', this.borderColor);
  
                  }  
  
              }
  
          },
  
          
  
          leadZero: function(v) {
  
              return v <= 9 ? '0' + v : v; 
  
          },
  
          
  
          destroy: function() {
  
              this.$widget.remove();
  
              this.$element.removeData('combodate').show();
  
          }
  
          
  
          //todo: clear method        
  
      };
  
  
  
      $.fn.combodate = function ( option ) {
  
          var d, args = Array.apply(null, arguments);
  
          args.shift();
  
  
  
          //getValue returns date as string / object (not jQuery object)
  
          if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) {
  
            return d.getValue.apply(d, args);
  
          }        
  
          
  
          return this.each(function () {
  
              var $this = $(this),
  
              data = $this.data('combodate'),
  
              options = typeof option == 'object' && option;
  
              if (!data) {
  
                  $this.data('combodate', (data = new Combodate(this, options)));
  
              }
  
              if (typeof option == 'string' && typeof data[option] == 'function') {
  
                  data[option].apply(data, args);
  
              }
  
          });
  
      };  
  
      
  
      $.fn.combodate.defaults = {
  
           //in this format value stored in original input
  
          format: 'DD-MM-YYYY HH:mm',      
  
          //in this format items in dropdowns are displayed
  
          template: 'D / MMM / YYYY   H : mm',
  
          //initial value, can be `new Date()`    
  
          value: null,                       
  
          minYear: 1970,
  
          maxYear: 2015,
  
          yearDescending: true,
  
          minuteStep: 5,
  
          secondStep: 1,
  
          firstItem: 'empty', //'name', 'empty', 'none'
  
          errorClass: null,
  
          roundTime: true //whether to round minutes and seconds if step > 1
  
      };
  
  
  
  }(window.jQuery));