diff --git a/src/containers/editable-popover.js b/src/containers/editable-popover.js
index ab540f2..027043e 100644
--- a/src/containers/editable-popover.js
+++ b/src/containers/editable-popover.js
@@ -15,9 +15,22 @@
$.extend(this.containerOptions, {
trigger: 'manual',
selector: false,
- content: ' '
+ content: ' ',
+ template: $.fn.popover.defaults.template
});
+
+ //as template property is used in inputs, hide it from popover
+ var t;
+ if(this.$element.data('template')) {
+ t = this.$element.data('template');
+ this.$element.removeData('template');
+ }
+
this.call(this.containerOptions);
+
+ if(t) {
+ this.$element.data('template', t);
+ }
},
setContainerOption: function(key, value) {
diff --git a/src/inputs/combodate/combodate.js b/src/inputs/combodate/combodate.js
new file mode 100644
index 0000000..6f25eb1
--- /dev/null
+++ b/src/inputs/combodate/combodate.js
@@ -0,0 +1,184 @@
+/**
+Combodate input - dropdown date and time picker.
+Based on [combodate](http://vitalets.github.com/combodate) plugin.
+To use it you should manually include [momentjs](http://momentjs.com).
+Allows to enter:
+
+* only date
+* only time
+* datetime
+
+Please note, that format is taken from momentjs and not compatible with bootstrap-datepicker / jquery UI datepicker.
+Internally value stored as Moment js object
+
+@class combodate
+@extends abstractinput
+@final
+@example
+<a href="#" id="dob" data-type="combodate" data-pk="1" data-url="/post" data-value="1984-05-15" data-original-title="Select date"></a>
+<script>
+$(function(){
+ $('#dob').editable({
+ format: 'YYYY-MM-DD',
+ viewformat: 'YYYY-MM-DD',
+ template: 'D / MMMM / YYYY',
+ combodate: {
+ minYear: 2000,
+ maxYear: 2015,
+ minuteStep: 1
+ }
+ }
+ });
+});
+</script>
+**/
+(function ($) {
+
+ var Constructor = function (options) {
+ this.init('combodate', options, Constructor.defaults);
+
+ //by default viewformat equals to format
+ if(!this.options.viewformat) {
+ this.options.viewformat = this.options.format;
+ }
+
+ //overriding combodate config (as by default jQuery extend() is not recursive)
+ this.options.combodate = $.extend({}, Constructor.defaults.combodate, options.combodate, {
+ format: this.options.format,
+ template: this.options.template
+ });
+ };
+
+ $.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
+
+ $.extend(Constructor.prototype, {
+ render: function () {
+ this.$input.combodate(this.options.combodate);
+
+ //"clear" link
+ /*
+ if(this.options.clear) {
+ this.$clear = $('<a href="#"></a>').html(this.options.clear).click($.proxy(function(e){
+ e.preventDefault();
+ e.stopPropagation();
+ this.clear();
+ }, this));
+
+ this.$tpl.parent().append($('<div class="editable-clear">').append(this.$clear));
+ }
+ */
+ },
+
+ value2html: function(value, element) {
+ var text = value ? value.format(this.options.viewformat) : '';
+ $(element).text(text);
+ },
+
+ html2value: function(html) {
+ return html ? moment(html, this.options.viewformat) : null;
+ },
+
+ value2str: function(value) {
+ return value ? value.format(this.options.format) : '';
+ },
+
+ str2value: function(str) {
+ return str ? moment(str, this.options.format) : null;
+ },
+
+ value2submit: function(value) {
+ return this.value2str(value);
+ },
+
+ value2input: function(value) {
+ this.$input.combodate('setValue', value);
+ },
+
+ input2value: function() {
+ return this.$input.combodate('getValue', null);
+ },
+
+ activate: function() {
+ this.$input.siblings('.combodate').find('select').eq(0).focus();
+ },
+
+ /*
+ clear: function() {
+ this.$input.data('datepicker').date = null;
+ this.$input.find('.active').removeClass('active');
+ },
+ */
+
+ autosubmit: function() {
+
+ }
+
+ });
+
+ Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
+ /**
+ @property tpl
+ @default <input type="text">
+ **/
+ tpl:'<input type="text">',
+ /**
+ @property inputclass
+ @default null
+ **/
+ inputclass: null,
+ /**
+ Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
+ See list of tokens in [momentjs docs](http://momentjs.com/docs/#/parsing/string-format)
+
+ @property format
+ @type string
+ @default YYYY-MM-DD
+ **/
+ format:'YYYY-MM-DD',
+ /**
+ Format used for displaying date. Also applied when converting date from element's text on init.
+ If not specified equals to `format`.
+
+ @property viewformat
+ @type string
+ @default null
+ **/
+ viewformat: null,
+ /**
+ Template used for displaying dropdowns.
+
+ @property template
+ @type string
+ @default D / MMM / YYYY
+ **/
+ template: 'D / MMM / YYYY',
+ /**
+ Configuration of combodate.
+ Full list of options: http://vitalets.github.com/combodate/#docs
+
+ @property datepicker
+ @type object
+ @default {
+ weekStart: 0,
+ startView: 0,
+ autoclose: false
+ }
+ **/
+ combodate: {
+ },
+
+ /*
+ (not implemented yet)
+ Text shown as clear date button.
+ If <code>false</code> clear button will not be rendered.
+
+ @property clear
+ @type boolean|string
+ @default 'x clear'
+ */
+ //clear: '× clear'
+ });
+
+ $.fn.editabletypes.combodate = Constructor;
+
+}(window.jQuery));
diff --git a/src/inputs/combodate/lib/combodate.js b/src/inputs/combodate/lib/combodate.js
new file mode 100644
index 0000000..e27adff
--- /dev/null
+++ b/src/inputs/combodate/lib/combodate.js
@@ -0,0 +1,398 @@
+/**
+* Combodate - 1.0.0
+* 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
+*
+* 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) {
+ var v = v[0],
+ r = new RegExp(v+'+'),
+ token = v.length > 1 ? v.substring(1, 2) : v;
+
+ tpl = tpl.replace(r, '{'+token+'}');
+ });
+
+ //replace spaces with
+ tpl = tpl.replace(/ /g, ' ');
+
+ //second pass
+ $.each(this.map, function(k, v) {
+ var v = v[0],
+ 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 = [];
+ if(this.options.firstItem === 'name') {
+ var header = typeof moment.relativeTime[key] === 'function' ? moment.relativeTime[key](1, true, key, false) : moment.relativeTime[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) {
+ name = moment.months[i];
+ } else if(shortNames) {
+ name = moment.monthsShort[i];
+ } else if(twoDigit) {
+ name = this.leadZero(i+1);
+ } else {
+ name = i+1;
+ }
+ items.push([i, name]);
+ }
+ return items;
+ },
+
+ /*
+ fill year
+ */
+ fillYear: function() {
+ var items = this.initItems('y'), 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.push([i, name]);
+ }
+ 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,
+ max = h12 ? 12 : 23;
+
+ for(i=0; 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.
+ 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 if 12h format
+ if(this.$ampm) {
+ values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
+ if(values.hour === 24) {
+ values.hour = 0;
+ }
+ }
+
+ 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 = {};
+
+ 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) {
+ if(values.hour > 12) {
+ values.hour -= 12;
+ values.ampm = 'pm';
+ } else {
+ values.ampm = 'am';
+ }
+ }
+
+ $.each(values, function(k, v) {
+ if(that['$'+k]) {
+ 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,
+ minuteStep: 5,
+ secondStep: 1,
+ firstItem: 'empty', //'name', 'empty', 'none'
+ errorClass: null
+ };
+
+}(window.jQuery));
\ No newline at end of file
diff --git a/src/inputs/combodate/lib/moment.min.js b/src/inputs/combodate/lib/moment.min.js
new file mode 100644
index 0000000..67cb152
--- /dev/null
+++ b/src/inputs/combodate/lib/moment.min.js
@@ -0,0 +1,6 @@
+// moment.js
+// version : 1.7.2
+// author : Tim Wood
+// license : MIT
+// momentjs.com
+(function(a){function E(a,b,c,d){var e=c.lang();return e[a].call?e[a](c,d):e[a][b]}function F(a,b){return function(c){return K(a.call(this,c),b)}}function G(a){return function(b){var c=a.call(this,b);return c+this.lang().ordinal(c)}}function H(a,b,c){this._d=a,this._isUTC=!!b,this._a=a._a||null,this._lang=c||!1}function I(a){var b=this._data={},c=a.years||a.y||0,d=a.months||a.M||0,e=a.weeks||a.w||0,f=a.days||a.d||0,g=a.hours||a.h||0,h=a.minutes||a.m||0,i=a.seconds||a.s||0,j=a.milliseconds||a.ms||0;this._milliseconds=j+i*1e3+h*6e4+g*36e5,this._days=f+e*7,this._months=d+c*12,b.milliseconds=j%1e3,i+=J(j/1e3),b.seconds=i%60,h+=J(i/60),b.minutes=h%60,g+=J(h/60),b.hours=g%24,f+=J(g/24),f+=e*7,b.days=f%30,d+=J(f/30),b.months=d%12,c+=J(d/12),b.years=c,this._lang=!1}function J(a){return a<0?Math.ceil(a):Math.floor(a)}function K(a,b){var c=a+"";while(c.length<b)c="0"+c;return c}function L(a,b,c){var d=b._milliseconds,e=b._days,f=b._months,g;d&&a._d.setTime(+a+d*c),e&&a.date(a.date()+e*c),f&&(g=a.date(),a.date(1).month(a.month()+f*c).date(Math.min(g,a.daysInMonth())))}function M(a){return Object.prototype.toString.call(a)==="[object Array]"}function N(a,b){var c=Math.min(a.length,b.length),d=Math.abs(a.length-b.length),e=0,f;for(f=0;f<c;f++)~~a[f]!==~~b[f]&&e++;return e+d}function O(a,b,c,d){var e,f,g=[];for(e=0;e<7;e++)g[e]=a[e]=a[e]==null?e===2?1:0:a[e];return a[7]=g[7]=b,a[8]!=null&&(g[8]=a[8]),a[3]+=c||0,a[4]+=d||0,f=new Date(0),b?(f.setUTCFullYear(a[0],a[1],a[2]),f.setUTCHours(a[3],a[4],a[5],a[6])):(f.setFullYear(a[0],a[1],a[2]),f.setHours(a[3],a[4],a[5],a[6])),f._a=g,f}function P(a,c){var d,e,g=[];!c&&h&&(c=require("./lang/"+a));for(d=0;d<i.length;d++)c[i[d]]=c[i[d]]||f.en[i[d]];for(d=0;d<12;d++)e=b([2e3,d]),g[d]=new RegExp("^"+(c.months[d]||c.months(e,""))+"|^"+(c.monthsShort[d]||c.monthsShort(e,"")).replace(".",""),"i");return c.monthsParse=c.monthsParse||g,f[a]=c,c}function Q(a){var c=typeof a=="string"&&a||a&&a._lang||null;return c?f[c]||P(c):b}function R(a){return a.match(/\[.*\]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function S(a){var b=a.match(k),c,d;for(c=0,d=b.length;c<d;c++)D[b[c]]?b[c]=D[b[c]]:b[c]=R(b[c]);return function(e){var f="";for(c=0;c<d;c++)f+=typeof b[c].call=="function"?b[c].call(e,a):b[c];return f}}function T(a,b){function d(b){return a.lang().longDateFormat[b]||b}var c=5;while(c--&&l.test(b))b=b.replace(l,d);return A[b]||(A[b]=S(b)),A[b](a)}function U(a){switch(a){case"DDDD":return p;case"YYYY":return q;case"S":case"SS":case"SSS":case"DDD":return o;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":case"a":case"A":return r;case"Z":case"ZZ":return s;case"T":return t;case"MM":case"DD":case"YY":case"HH":case"hh":case"mm":case"ss":case"M":case"D":case"d":case"H":case"h":case"m":case"s":return n;default:return new RegExp(a.replace("\\",""))}}function V(a,b,c,d){var e,f;switch(a){case"M":case"MM":c[1]=b==null?0:~~b-1;break;case"MMM":case"MMMM":for(e=0;e<12;e++)if(Q().monthsParse[e].test(b)){c[1]=e,f=!0;break}f||(c[8]=!1);break;case"D":case"DD":case"DDD":case"DDDD":b!=null&&(c[2]=~~b);break;case"YY":c[0]=~~b+(~~b>70?1900:2e3);break;case"YYYY":c[0]=~~Math.abs(b);break;case"a":case"A":d.isPm=(b+"").toLowerCase()==="pm";break;case"H":case"HH":case"h":case"hh":c[3]=~~b;break;case"m":case"mm":c[4]=~~b;break;case"s":case"ss":c[5]=~~b;break;case"S":case"SS":case"SSS":c[6]=~~(("0."+b)*1e3);break;case"Z":case"ZZ":d.isUTC=!0,e=(b+"").match(x),e&&e[1]&&(d.tzh=~~e[1]),e&&e[2]&&(d.tzm=~~e[2]),e&&e[0]==="+"&&(d.tzh=-d.tzh,d.tzm=-d.tzm)}b==null&&(c[8]=!1)}function W(a,b){var c=[0,0,1,0,0,0,0],d={tzh:0,tzm:0},e=b.match(k),f,g;for(f=0;f<e.length;f++)g=(U(e[f]).exec(a)||[])[0],g&&(a=a.slice(a.indexOf(g)+g.length)),D[e[f]]&&V(e[f],g,c,d);return d.isPm&&c[3]<12&&(c[3]+=12),d.isPm===!1&&c[3]===12&&(c[3]=0),O(c,d.isUTC,d.tzh,d.tzm)}function X(a,b){var c,d=a.match(m)||[],e,f=99,g,h,i;for(g=0;g<b.length;g++)h=W(a,b[g]),e=T(new H(h),b[g]).match(m)||[],i=N(d,e),i<f&&(f=i,c=h);return c}function Y(a){var b="YYYY-MM-DDT",c;if(u.exec(a)){for(c=0;c<4;c++)if(w[c][1].exec(a)){b+=w[c][0];break}return s.exec(a)?W(a,b+" Z"):W(a,b)}return new Date(a)}function Z(a,b,c,d,e){var f=e.relativeTime[a];return typeof f=="function"?f(b||1,!!c,a,d):f.replace(/%d/i,b||1)}function $(a,b,c){var e=d(Math.abs(a)/1e3),f=d(e/60),g=d(f/60),h=d(g/24),i=d(h/365),j=e<45&&["s",e]||f===1&&["m"]||f<45&&["mm",f]||g===1&&["h"]||g<22&&["hh",g]||h===1&&["d"]||h<=25&&["dd",h]||h<=45&&["M"]||h<345&&["MM",d(h/30)]||i===1&&["y"]||["yy",i];return j[2]=b,j[3]=a>0,j[4]=c,Z.apply({},j)}function _(a,c){b.fn[a]=function(a){var b=this._isUTC?"UTC":"";return a!=null?(this._d["set"+b+c](a),this):this._d["get"+b+c]()}}function ab(a){b.duration.fn[a]=function(){return this._data[a]}}function bb(a,c){b.duration.fn["as"+a]=function(){return+this/c}}var b,c="1.7.2",d=Math.round,e,f={},g="en",h=typeof module!="undefined"&&module.exports,i="months|monthsShort|weekdays|weekdaysShort|weekdaysMin|longDateFormat|calendar|relativeTime|ordinal|meridiem".split("|"),j=/^\/?Date\((\-?\d+)/i,k=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?|.)/g,l=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?)/g,m=/([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,n=/\d\d?/,o=/\d{1,3}/,p=/\d{3}/,q=/\d{1,4}/,r=/[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+/i,s=/Z|[\+\-]\d\d:?\d\d/i,t=/T/i,u=/^\s*\d{4}-\d\d-\d\d(T(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,v="YYYY-MM-DDTHH:mm:ssZ",w=[["HH:mm:ss.S",/T\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/T\d\d:\d\d:\d\d/],["HH:mm",/T\d\d:\d\d/],["HH",/T\d\d/]],x=/([\+\-]|\d\d)/gi,y="Month|Date|Hours|Minutes|Seconds|Milliseconds".split("|"),z={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},A={},B="DDD w M D d".split(" "),C="M D H h m s w".split(" "),D={M:function(){return this.month()+1},MMM:function(a){return E("monthsShort",this.month(),this,a)},MMMM:function(a){return E("months",this.month(),this,a)},D:function(){return this.date()},DDD:function(){var a=new Date(this.year(),this.month(),this.date()),b=new Date(this.year(),0,1);return~~((a-b)/864e5+1.5)},d:function(){return this.day()},dd:function(a){return E("weekdaysMin",this.day(),this,a)},ddd:function(a){return E("weekdaysShort",this.day(),this,a)},dddd:function(a){return E("weekdays",this.day(),this,a)},w:function(){var a=new Date(this.year(),this.month(),this.date()-this.day()+5),b=new Date(a.getFullYear(),0,4);return~~((a-b)/864e5/7+1.5)},YY:function(){return K(this.year()%100,2)},YYYY:function(){return K(this.year(),4)},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return~~(this.milliseconds()/100)},SS:function(){return K(~~(this.milliseconds()/10),2)},SSS:function(){return K(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return a<0&&(a=-a,b="-"),b+K(~~(a/60),2)+":"+K(~~a%60,2)},ZZ:function(){var a=-this.zone(),b="+";return a<0&&(a=-a,b="-"),b+K(~~(10*a/6),4)}};while(B.length)e=B.pop(),D[e+"o"]=G(D[e]);while(C.length)e=C.pop(),D[e+e]=F(D[e],2);D.DDDD=F(D.DDD,3),b=function(c,d){if(c===null||c==="")return null;var e,f;return b.isMoment(c)?new H(new Date(+c._d),c._isUTC,c._lang):(d?M(d)?e=X(c,d):e=W(c,d):(f=j.exec(c),e=c===a?new Date:f?new Date(+f[1]):c instanceof Date?c:M(c)?O(c):typeof c=="string"?Y(c):new Date(c)),new H(e))},b.utc=function(a,c){return M(a)?new H(O(a,!0),!0):(typeof a=="string"&&!s.exec(a)&&(a+=" +0000",c&&(c+=" Z")),b(a,c).utc())},b.unix=function(a){return b(a*1e3)},b.duration=function(a,c){var d=b.isDuration(a),e=typeof a=="number",f=d?a._data:e?{}:a,g;return e&&(c?f[c]=a:f.milliseconds=a),g=new I(f),d&&(g._lang=a._lang),g},b.humanizeDuration=function(a,c,d){return b.duration(a,c===!0?null:c).humanize(c===!0?!0:d)},b.version=c,b.defaultFormat=v,b.lang=function(a,c){var d;if(!a)return g;(c||!f[a])&&P(a,c);if(f[a]){for(d=0;d<i.length;d++)b[i[d]]=f[a][i[d]];b.monthsParse=f[a].monthsParse,g=a}},b.langData=Q,b.isMoment=function(a){return a instanceof H},b.isDuration=function(a){return a instanceof I},b.lang("en",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},ordinal:function(a){var b=a%10;return~~(a%100/10)===1?"th":b===1?"st":b===2?"nd":b===3?"rd":"th"}}),b.fn=H.prototype={clone:function(){return b(this)},valueOf:function(){return+this._d},unix:function(){return Math.floor(+this._d/1e3)},toString:function(){return this._d.toString()},toDate:function(){return this._d},toArray:function(){var a=this;return[a.year(),a.month(),a.date(),a.hours(),a.minutes(),a.seconds(),a.milliseconds(),!!this._isUTC]},isValid:function(){return this._a?this._a[8]!=null?!!this._a[8]:!N(this._a,(this._a[7]?b.utc(this._a):b(this._a)).toArray()):!isNaN(this._d.getTime())},utc:function(){return this._isUTC=!0,this},local:function(){return this._isUTC=!1,this},format:function(a){return T(this,a?a:b.defaultFormat)},add:function(a,c){var d=c?b.duration(+c,a):b.duration(a);return L(this,d,1),this},subtract:function(a,c){var d=c?b.duration(+c,a):b.duration(a);return L(this,d,-1),this},diff:function(a,c,e){var f=this._isUTC?b(a).utc():b(a).local(),g=(this.zone()-f.zone())*6e4,h=this._d-f._d-g,i=this.year()-f.year(),j=this.month()-f.month(),k=this.date()-f.date(),l;return c==="months"?l=i*12+j+k/30:c==="years"?l=i+(j+k/30)/12:l=c==="seconds"?h/1e3:c==="minutes"?h/6e4:c==="hours"?h/36e5:c==="days"?h/864e5:c==="weeks"?h/6048e5:h,e?l:d(l)},from:function(a,c){return b.duration(this.diff(a)).lang(this._lang).humanize(!c)},fromNow:function(a){return this.from(b(),a)},calendar:function(){var a=this.diff(b().sod(),"days",!0),c=this.lang().calendar,d=c.sameElse,e=a<-6?d:a<-1?c.lastWeek:a<0?c.lastDay:a<1?c.sameDay:a<2?c.nextDay:a<7?c.nextWeek:d;return this.format(typeof e=="function"?e.apply(this):e)},isLeapYear:function(){var a=this.year();return a%4===0&&a%100!==0||a%400===0},isDST:function(){return this.zone()<b([this.year()]).zone()||this.zone()<b([this.year(),5]).zone()},day:function(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return a==null?b:this.add({d:a-b})},startOf:function(a){switch(a.replace(/s$/,"")){case"year":this.month(0);case"month":this.date(1);case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return this},endOf:function(a){return this.startOf(a).add(a.replace(/s?$/,"s"),1).subtract("ms",1)},sod:function(){return this.clone().startOf("day")},eod:function(){return this.clone().endOf("day")},zone:function(){return this._isUTC?0:this._d.getTimezoneOffset()},daysInMonth:function(){return b.utc([this.year(),this.month()+1,0]).date()},lang:function(b){return b===a?Q(this):(this._lang=b,this)}};for(e=0;e<y.length;e++)_(y[e].toLowerCase(),y[e]);_("year","FullYear"),b.duration.fn=I.prototype={weeks:function(){return J(this.days()/7)},valueOf:function(){return this._milliseconds+this._days*864e5+this._months*2592e6},humanize:function(a){var b=+this,c=this.lang().relativeTime,d=$(b,!a,this.lang()),e=b<=0?c.past:c.future;return a&&(typeof e=="function"?d=e(d):d=e.replace(/%s/i,d)),d},lang:b.fn.lang};for(e in z)z.hasOwnProperty(e)&&(bb(e,z[e]),ab(e.toLowerCase()));bb("Weeks",6048e5),h&&(module.exports=b),typeof ender=="undefined"&&(this.moment=b),typeof define=="function"&&define.amd&&define("moment",[],function(){return b})}).call(this);
\ No newline at end of file
diff --git a/test/loader.js b/test/loader.js
index 5fa9de7..291c881 100644
--- a/test/loader.js
+++ b/test/loader.js
@@ -31,6 +31,7 @@ define(function () {
loadCss(require.toUrl("./editable-element.css"));
}
},
+ //default inputs
'editable-form/editable-form': {
deps: ['require',
'inputs/text',
@@ -38,6 +39,7 @@ define(function () {
'inputs/select',
'inputs/checklist',
'inputs/html5types',
+ 'inputs/combodate/combodate',
'inputs-ext/address/address'],
init: function(require) {
loadCss(require.toUrl("./editable-form.css"));
@@ -49,7 +51,8 @@ define(function () {
'inputs/text': ['inputs/abstract'],
'inputs/textarea': ['inputs/abstract'],
'inputs/abstract': ['editable-form/editable-form-utils'],
- 'inputs/html5types': ['inputs/text'],
+ 'inputs/html5types': ['inputs/text'],
+ 'inputs/combodate/combodate': ['inputs/abstract', 'inputs/combodate/lib/combodate', 'inputs/combodate/lib/moment.min'],
/*
bootstrap
diff --git a/test/main.js b/test/main.js
index ee32ab3..0863c1c 100644
--- a/test/main.js
+++ b/test/main.js
@@ -44,7 +44,8 @@ require(["loader", jqurl], function(loader) {
'test/unit/text',
'test/unit/textarea',
'test/unit/select',
- 'test/unit/checklist'
+ 'test/unit/checklist',
+ 'test/unit/combodate'
];
tests = tests.concat(custom);
tests.push('test/unit/api');
diff --git a/test/unit/combodate.js b/test/unit/combodate.js
new file mode 100644
index 0000000..7e0f275
--- /dev/null
+++ b/test/unit/combodate.js
@@ -0,0 +1,107 @@
+$(function () {
+
+ //formats
+ var
+ fd = 'DD.MM.YYYY', vfd = 'DD-MM-YYYY', vd = '15-05-1984',
+ fdt = 'DD-MM-YYYY hh:mm:ss A', vfdt = 'DD MMM YYYY h:m:s a', vdt = '15-05-1984 08:20:30 PM';
+
+
+ module("combodate", {
+ setup: function(){
+ fx = $('#async-fixture');
+ $.support.transition = false;
+ }
+ });
+
+ asyncTest("container should contain combodate and save new value (date)", function () {
+
+ var e = $('<a href="#" data-type="combodate" data-pk="1" data-url="/combodate">'+vd+'</a>').appendTo(fx).editable({
+ format: fd,
+ viewformat: vfd,
+ template: fd
+ }),
+ m = moment(vd, vfd);
+
+ $.mockjax({
+ url: '/combodate',
+ response: function(settings) {
+ equal(settings.data.value, m.format(fd), 'submitted value correct');
+ }
+ });
+
+ equal(e.data('editable').value.format(fd), m.format(fd), 'init value correct');
+
+ e.click();
+ var p = tip(e);
+ ok(p.find('.combodate').is(':visible'), 'combodate exists');
+ equal(p.find('.day, .month, .year, .hour, .minute').length, 3, 'combos correct');
+
+ equal(p.find('.day').val(), m.date(), 'day set correct');
+ equal(p.find('.month').val(), m.month(), 'month set correct');
+ equal(p.find('.year').val(), m.year(), 'year set correct');
+
+ //set new day
+ p.find('.day').val(16).trigger('change');
+ m.date(16);
+ p.find('form').submit();
+
+ setTimeout(function() {
+ ok(!p.is(':visible'), 'container closed');
+ equal(e.data('editable').value.format(fd), m.format(fd), 'new value correct');
+ equal(e.text(), m.format(vfd), 'new text correct');
+ e.remove();
+ start();
+ }, timeout);
+
+ });
+
+ asyncTest("container should contain combodate and save new value (datetime)", function () {
+
+ var e = $('<a href="#" data-type="combodate" data-pk="1" data-url="/combodate-dt" data-value="'+vdt+'"></a>').appendTo(fx).editable({
+ format: fdt,
+ viewformat: vfdt,
+ template: fdt
+ }),
+ m = moment(vdt, fdt);
+
+ $.mockjax({
+ url: '/combodate-dt',
+ response: function(settings) {
+ equal(settings.data.value, m.format(fdt), 'submitted value correct');
+ }
+ });
+
+ equal(e.data('editable').value.format(fdt), m.format(fdt), 'init value correct');
+ equal(e.text(), m.format(vfdt), 'init text correct');
+
+ e.click();
+ var p = tip(e);
+ ok(p.find('.combodate').is(':visible'), 'combodate exists');
+ equal(p.find('.day, .month, .year, .hour, .minute, .second, .ampm').length, 7, 'combos correct');
+
+ equal(p.find('.day').val(), m.date(), 'day set correct');
+ equal(p.find('.month').val(), m.month(), 'month set correct');
+ equal(p.find('.year').val(), m.year(), 'year set correct');
+ equal(p.find('.hour').val(), m.hours()-12, 'hour set correct');
+ equal(p.find('.minute').val(), m.minutes(), 'minute set correct');
+ equal(p.find('.second').val(), m.seconds(), 'second set correct');
+ equal(p.find('.ampm').val(), 'pm', 'ampm set correct');
+
+ //set new day
+ p.find('.day').val(16).trigger('change');
+ p.find('.hour').val(9).trigger('change');
+ m.date(16);
+ m.hours(21);
+ p.find('form').submit();
+
+ setTimeout(function() {
+ ok(!p.is(':visible'), 'container closed');
+ equal(e.data('editable').value.format(fdt), m.format(fdt), 'new value correct');
+ equal(e.text(), m.format(vfdt), 'new text correct');
+ e.remove();
+ start();
+ }, timeout);
+
+ });
+
+});
\ No newline at end of file