diff --git a/bower.json b/bower.json index 983845b..442284d 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "bootstrap-datetime", - "version": "1.0.5", + "version": "1.0.6", "description": "Bootstrap datetime picker", "authors": [ { diff --git a/dist/js/bootstrap-datetime/main.js b/dist/js/bootstrap-datetime/main.js index 88cf416..c2b90df 100644 --- a/dist/js/bootstrap-datetime/main.js +++ b/dist/js/bootstrap-datetime/main.js @@ -1,2 +1,2 @@ -define("bootstrap-datetime/util",[],function(){return exports={},exports.el=function(t,e){var n=document.createElement(t);return n.className=e,n},exports}),define("bootstrap-datetime/date-view",["moment","./util"],function(t,e){function n(t){for(;t.tbody.firstChild;)t.tbody.removeChild(t.tbody.firstChild)}function i(t,n,i){var a=e.el("a","btn btn-xs btn-default");return a.href="#",a.setAttribute("data-id",t),a.innerHTML=n,a.onclick=i,a}function a(n){var i,a=e.el("table","table table-condensed table-striped"),r=e.el("thead"),o=e.el("tr");n.tbody=e.el("tbody"),a.appendChild(r),r.appendChild(o),a.appendChild(n.tbody);for(var d=t.weekdaysShort(),l=0;ll;l++)d.appendChild(e.el("td"));var v=i.dt.month()===i.visibleDateTime.month()&&i.dt.year()===i.visibleDateTime.year();for(u=0;uu;u++)d.appendChild(e.el("td")),l++}function l(t){d(t,t.visibleDateTime.add(1,"months"))}function u(t){d(t,t.visibleDateTime.subtract(1,"months"))}function p(e){var n=t();e.dt&&e.dt.isValid()?(e.dt.date(n.date()),e.dt.month(n.month()),e.dt.year(n.year())):e.dt=n,e.updateCallback(e.dt)}function s(t){var n=this;this.footerButton=i("today-btn",c.TODAY,function(t){t.preventDefault(),p(n)}),this.icon="calendar",this.updateCallback=t,this.closeOnUpdate=!0,this.header=e.el("h3","panel-title"),this.titleContents=[i("previous-btn",'',function(t){t.preventDefault(),u(n)}),this.header,i("next-btn",'',function(t){t.preventDefault(),l(n)})],this.bodyContents=[a(n)],this.bodyDataId="date-content"}var c={TODAY:"Today"};return s.prototype.update=function(t){this.dt=t,d(this,this.dt)},s}),define("bootstrap-datetime/time-view",["moment","./util"],function(t,e){function n(t,n,i,a,r){var o=e.el("a","btn btn-default");return o.href="#",i&&(o.className+=" "+i),o.setAttribute("data-id",n),o.innerHTML=a,o.onclick=function(e){e.preventDefault(),r(t,e)},o}function i(e){e.dt&&e.dt.isValid()||(e.dt=t()),e.dt.hour(e.hourInput.value),e.dt.minute(e.minuteInput.value),e.dt.second(e.secondInput.value),e.updateCallback(e.dt)}function a(t){t.closeOnUpdate=!0,t.updateCallback(t.dt),t.closeOnUpdate=!1}function r(t,e){var n=e.currentTarget,a=null,r=59;switch(n.getAttribute("data-id")){case"hour-down-btn":a=t.hourInput,r=23;break;case"minute-down-btn":a=t.minuteInput;break;default:a=t.secondInput}var o=parseInt(a.value);a.value=isNaN(o)||0===o?r:--o,i(t)}function o(t,e){var n=e.currentTarget,a=null,r=59;switch(n.getAttribute("data-id")){case"hour-up-btn":a=t.hourInput,r=23;break;case"minute-up-btn":a=t.minuteInput;break;default:a=t.secondInput}var o=parseInt(a.value);a.value=isNaN(o)||o===r?0:++o,i(t)}function d(t,i){var a=e.el("div","col-md-4 text-center"),d=n(t,i+"-up-btn","",'',o),l=n(t,i+"-down-btn","",'',r),u=e.el("input","form-control");return u.maxLength=2,u.setAttribute("data-id",i+"-input"),a.appendChild(d),a.appendChild(u),a.appendChild(l),a}function l(e){var n=t();e.dt&&e.dt.isValid()?(e.dt.hour(n.hour()),e.dt.minute(n.minute()),e.dt.second(n.second())):(e.dt=n,e.dt.hour(0),e.dt.minute(0),e.dt.second(0)),e.closeOnUpdate=!0,e.updateCallback(e.dt),e.closeOnUpdate=!1}function u(t,e){t.hourInput.value=e.hour(),t.minuteInput.value=e.minute(),t.secondInput.value=e.second()}function p(t){this.icon="time",this.footerButton=n(this,"now-btn","btn-xs",s.NOW,l),this.closeOnUpdate=!1;var i=e.el("div","clearfix"),r=d(this,"hour"),o=d(this,"minute"),u=d(this,"second");this.hourInput=r.children[1],this.minuteInput=o.children[1],this.secondInput=u.children[1];var p=e.el("a","btn btn-xs btn-default pull-right");p.href="#",p.textContent=s.DONE,p.setAttribute("data-id","done-btn");var c=this;p.onclick=function(t){t.preventDefault(),a(c)},this.bodyContents=[r,o,u,p,i],this.titleContents=null,this.bodyDataId="time-content",this.updateCallback=t}var s={DONE:"Done",NOW:"Now"};return p.prototype.update=function(t){this.dt=t,u(this,this.dt)},p}),define("bootstrap-datetime/main",["./date-view","moment","./time-view","./util"],function(t,e,n,i){function a(t){for(;t.btnGroup.previousElementSibling;)t.btnGroup.parentNode.removeChild(t.btnGroup.previousElementSibling);t.btnGroup.parentNode.insertBefore(t.views[t.currentView].footerButton,t.btnGroup)}function r(t){var e=t.btnGroup.querySelector(".active");if(e&&e.className.indexOf("active")&&(e.className=e.className.replace("active","")),t.btnGroup.children.length>t.currentView){var n=t.btnGroup.children[t.currentView];n.className.indexOf("active")<0&&(n.className+=" active")}}function o(t,e){for(var n,i=e.titleContents,o=t.popover.children[1],d=e.bodyContents,l=t.popover.children[2];o.firstChild;)o.removeChild(o.firstChild);for(;l.firstChild;)l.removeChild(l.firstChild);if(i){for(n=0;nl;l++)d.appendChild(e.el("td"));var v=i.dt.month()===i.visibleDateTime.month()&&i.dt.year()===i.visibleDateTime.year();for(u=0;uu;u++)d.appendChild(e.el("td")),l++}function l(t){d(t,t.visibleDateTime.add(1,"months"))}function u(t){d(t,t.visibleDateTime.subtract(1,"months"))}function p(e){var n=t();e.dt&&e.dt.isValid()?(e.dt.date(n.date()),e.dt.month(n.month()),e.dt.year(n.year())):e.dt=n,e.updateCallback(e.dt)}function s(t){var n=this;this.footerButton=i("today-btn",c.TODAY,function(t){t.preventDefault(),p(n)}),this.icon="calendar",this.updateCallback=t,this.closeOnUpdate=!0,this.header=e.el("h3","panel-title"),this.titleContents=[i("previous-btn",'',function(t){t.preventDefault(),u(n)}),this.header,i("next-btn",'',function(t){t.preventDefault(),l(n)})],this.bodyContents=[a(n)],this.bodyDataId="date-content"}var c={TODAY:"Today"};return s.prototype.update=function(t){this.dt=t,d(this,this.dt)},s}),define("bootstrap-datetime/time-view",["moment","./util"],function(t,e){function n(t,n,i,a,r){var o=e.el("a","btn btn-default");return o.href="#",i&&(o.className+=" "+i),o.setAttribute("data-id",n),o.innerHTML=a,o.onclick=function(e){e.preventDefault(),r(t,e)},o}function i(e){e.dt&&e.dt.isValid()||(e.dt=t()),e.dt.hour(e.hourInput.value),e.dt.minute(e.minuteInput.value),e.dt.second(e.secondInput.value),e.updateCallback(e.dt)}function a(t){t.closeOnUpdate=!0,t.updateCallback(t.dt),t.closeOnUpdate=!1}function r(t,e){var n=e.currentTarget,a=null,r=59;switch(n.getAttribute("data-id")){case"hour-down-btn":a=t.hourInput,r=23;break;case"minute-down-btn":a=t.minuteInput;break;default:a=t.secondInput}var o=parseInt(a.value);a.value=isNaN(o)||0===o?r:--o,i(t)}function o(t,e){var n=e.currentTarget,a=null,r=59;switch(n.getAttribute("data-id")){case"hour-up-btn":a=t.hourInput,r=23;break;case"minute-up-btn":a=t.minuteInput;break;default:a=t.secondInput}var o=parseInt(a.value);a.value=isNaN(o)||o===r?0:++o,i(t)}function d(t,i){var a=e.el("div","col-md-4 text-center"),d=n(t,i+"-up-btn","",'',o),l=n(t,i+"-down-btn","",'',r),u=e.el("input","form-control");return u.maxLength=2,u.setAttribute("data-id",i+"-input"),a.appendChild(d),a.appendChild(u),a.appendChild(l),a}function l(e){var n=t();e.dt&&e.dt.isValid()?(e.dt.hour(n.hour()),e.dt.minute(n.minute()),e.dt.second(n.second())):(e.dt=n,e.dt.hour(0),e.dt.minute(0),e.dt.second(0)),e.closeOnUpdate=!0,e.updateCallback(e.dt),e.closeOnUpdate=!1}function u(t,e){t.hourInput.value=e.hour(),t.minuteInput.value=e.minute(),t.secondInput.value=e.second()}function p(t){this.icon="time",this.footerButton=n(this,"now-btn","btn-xs",s.NOW,l),this.closeOnUpdate=!1;var i=e.el("div","clearfix"),r=d(this,"hour"),o=d(this,"minute"),u=d(this,"second");this.hourInput=r.children[1],this.minuteInput=o.children[1],this.secondInput=u.children[1];var p=e.el("a","btn btn-xs btn-default pull-right");p.href="#",p.textContent=s.DONE,p.setAttribute("data-id","done-btn");var c=this;p.onclick=function(t){t.preventDefault(),a(c)},this.bodyContents=[r,o,u,p,i],this.titleContents=null,this.bodyDataId="time-content",this.updateCallback=t}var s={DONE:"Done",NOW:"Now"};return p.prototype.update=function(t){this.dt=t,u(this,this.dt)},p}),define("bootstrap-datetime/main",["./date-view","moment","./time-view","./util"],function(t,e,n,i){function a(t){for(;t.btnGroup.previousElementSibling;)t.btnGroup.parentNode.removeChild(t.btnGroup.previousElementSibling);t.btnGroup.parentNode.insertBefore(t.views[t.currentView].footerButton,t.btnGroup)}function r(t){var e=t.btnGroup.querySelector(".active");if(e&&e.className.indexOf("active")&&(e.className=e.className.replace("active","")),t.btnGroup.children.length>t.currentView){var n=t.btnGroup.children[t.currentView];n.className.indexOf("active")<0&&(n.className+=" active")}}function o(t,e){for(var n,i=e.titleContents,o=t.popover.children[1],d=e.bodyContents,l=t.popover.children[2];o.firstChild;)o.removeChild(o.firstChild);for(;l.firstChild;)l.removeChild(l.firstChild);if(i){for(n=0;n', function (e) {\n e.preventDefault();\n previousMonthClickHandler(self);\n }),\n this.header,\n createButton('next-btn', '', function (e) {\n e.preventDefault();\n nextMonthClickHandler(self);\n }),\n ];\n\n this.bodyContents = [\n createCalendar(self),\n ];\n\n this.bodyDataId = 'date-content';\n }\n\n DateView.prototype.update = function (dateTime) {\n this.dt = dateTime;\n\n updateUI(this, this.dt);\n };\n\n return DateView;\n});\n\n","/**\n * @module TimeView\n * @returns {TimeView} picker view for times\n */\ndefine('bootstrap-datetime/time-view',[\n 'moment',\n './util',\n], function (\n moment,\n util\n) {\n 'use strict';\n\n var localeText = {\n DONE: 'Done',\n NOW: 'Now',\n };\n\n function createButton(timeView, dataId, additionalClassName, contents, clickHandler) {\n var button = util.el('a', 'btn btn-default');\n button.href = '#';\n\n if (additionalClassName) {\n button.className += ' ' + additionalClassName;\n }\n\n button.setAttribute('data-id', dataId);\n button.innerHTML = contents;\n button.onclick = function (e) {\n e.preventDefault();\n clickHandler(timeView, e);\n };\n\n return button;\n }\n\n function updateTime(timeView) {\n if (!timeView.dt || !timeView.dt.isValid()) {\n timeView.dt = moment();\n }\n\n timeView.dt.hour(timeView.hourInput.value);\n timeView.dt.minute(timeView.minuteInput.value);\n timeView.dt.second(timeView.secondInput.value);\n\n timeView.updateCallback(timeView.dt);\n }\n\n function doneClickHandler(timeView) {\n timeView.closeOnUpdate = true;\n timeView.updateCallback(timeView.dt);\n timeView.closeOnUpdate = false;\n }\n\n function downClickHandler(timeView, e) {\n var btn = e.currentTarget;\n var input = null;\n var max = 59;\n\n switch (btn.getAttribute('data-id')) {\n case 'hour-down-btn':\n input = timeView.hourInput;\n max = 23;\n break;\n\n case 'minute-down-btn':\n input = timeView.minuteInput;\n break;\n\n default: // second-down-btn\n input = timeView.secondInput;\n }\n\n var val = parseInt(input.value);\n\n if (isNaN(val) || val === 0) {\n input.value = max;\n } else {\n input.value = --val;\n }\n\n updateTime(timeView);\n }\n\n function upClickHandler(timeView, e) {\n var btn = e.currentTarget;\n var input = null;\n var max = 59;\n\n switch (btn.getAttribute('data-id')) {\n case 'hour-up-btn':\n input = timeView.hourInput;\n max = 23;\n break;\n\n case 'minute-up-btn':\n input = timeView.minuteInput;\n break;\n\n default: // second-up-btn\n input = timeView.secondInput;\n }\n\n var val = parseInt(input.value);\n\n if (isNaN(val) || val === max) {\n input.value = 0;\n } else {\n input.value = ++val;\n }\n\n updateTime(timeView);\n }\n\n function createNumericPicker(timeView, dataId) {\n var div = util.el('div', 'col-md-4 text-center');\n\n var upBtn = createButton(timeView, dataId + '-up-btn', '', '', upClickHandler);\n var downBtn = createButton(timeView, dataId + '-down-btn', '', '', downClickHandler);\n var input = util.el('input', 'form-control');\n input.maxLength = 2;\n input.setAttribute('data-id', dataId + '-input');\n\n div.appendChild(upBtn);\n div.appendChild(input);\n div.appendChild(downBtn);\n\n return div;\n }\n\n function nowClickHandler(timeView) {\n var now = moment();\n\n // If input already has a DateTime update date (keeping time the same)\n if (timeView.dt && timeView.dt.isValid()) {\n timeView.dt.hour(now.hour());\n timeView.dt.minute(now.minute());\n timeView.dt.second(now.second());\n // Otherwise set date and zero out time\n } else {\n timeView.dt = now;\n timeView.dt.hour(0);\n timeView.dt.minute(0);\n timeView.dt.second(0);\n }\n\n timeView.closeOnUpdate = true;\n timeView.updateCallback(timeView.dt);\n timeView.closeOnUpdate = false;\n }\n\n function updateUI(dateView, dateTime) {\n dateView.hourInput.value = dateTime.hour();\n dateView.minuteInput.value = dateTime.minute();\n dateView.secondInput.value = dateTime.second();\n }\n\n function TimeView(updateCallback) {\n this.icon = 'time';\n this.footerButton = createButton(this, 'now-btn', 'btn-xs', localeText.NOW, nowClickHandler);\n this.closeOnUpdate = false;\n\n var clearDiv = util.el('div', 'clearfix');\n\n var hourPicker = createNumericPicker(this, 'hour');\n var minutePicker = createNumericPicker(this, 'minute');\n var secondPicker = createNumericPicker(this, 'second');\n\n this.hourInput = hourPicker.children[1];\n this.minuteInput = minutePicker.children[1];\n this.secondInput = secondPicker.children[1];\n\n var doneBtn = util.el('a', 'btn btn-xs btn-default pull-right');\n doneBtn.href = '#';\n doneBtn.textContent = localeText.DONE;\n doneBtn.setAttribute('data-id', 'done-btn');\n\n var self = this;\n\n doneBtn.onclick = function (e) {\n e.preventDefault();\n doneClickHandler(self);\n };\n\n this.bodyContents = [\n hourPicker,\n minutePicker,\n secondPicker,\n doneBtn,\n clearDiv,\n ];\n\n this.titleContents = null;\n this.bodyDataId = 'time-content';\n this.updateCallback = updateCallback;\n }\n\n TimeView.prototype.update = function (datetime) {\n this.dt = datetime;\n\n updateUI(this, this.dt);\n };\n\n return TimeView;\n});\n\n","/**\n * @module main\n */\ndefine('bootstrap-datetime/main',[\n './date-view',\n 'moment',\n './time-view',\n './util',\n], function (\n DateView,\n moment,\n TimeView,\n util\n) {\n 'use strict';\n\n function addViewFooterBtn(picker) {\n while (picker.btnGroup.previousElementSibling) {\n picker.btnGroup.parentNode.removeChild(picker.btnGroup.previousElementSibling);\n }\n\n picker.btnGroup.parentNode.insertBefore(picker.views[picker.currentView].footerButton, picker.btnGroup);\n }\n\n function updateActiveViewBtn(picker) {\n var activeBtn = picker.btnGroup.querySelector('.active');\n\n if (activeBtn && activeBtn.className.indexOf('active')) {\n activeBtn.className = activeBtn.className.replace('active', '');\n }\n\n if (picker.btnGroup.children.length > picker.currentView) {\n var currentBtn = picker.btnGroup.children[picker.currentView];\n\n if (currentBtn.className.indexOf('active') < 0) {\n currentBtn.className += ' active';\n }\n }\n }\n\n function renderView(picker, view) {\n var i;\n var titleContents = view.titleContents;\n var titleDiv = picker.popover.children[1];\n var bodyContents = view.bodyContents;\n var bodyDiv = picker.popover.children[2];\n\n // Remove current children from popover title\n while (titleDiv.firstChild) {\n titleDiv.removeChild(titleDiv.firstChild);\n }\n\n // Remove current children from popover body\n while (bodyDiv.firstChild) {\n bodyDiv.removeChild(bodyDiv.firstChild);\n }\n\n if (titleContents) {\n // Add title contents from view\n for (i = 0; i < titleContents.length; i++) {\n titleDiv.appendChild(titleContents[i]);\n }\n\n titleDiv.style.display = 'block';\n } else {\n titleDiv.style.display = 'none';\n }\n\n if (bodyContents) {\n // Add title contents from view\n for (i = 0; i < bodyContents.length; i++) {\n bodyDiv.appendChild(bodyContents[i]);\n }\n\n bodyDiv.style.display = 'block';\n } else {\n bodyDiv.style.display = 'none';\n }\n\n bodyDiv.setAttribute('data-id', view.bodyDataId);\n\n updateActiveViewBtn(picker);\n addViewFooterBtn(picker);\n }\n\n function viewClickHandler(picker, e) {\n picker.currentInput = e.currentTarget;\n\n var index = parseInt(picker.currentInput.getAttribute('data-index'));\n\n // If clicked view is current view nothing to do\n if (index === picker.currentView) {\n return;\n }\n\n picker.currentView = index;\n\n renderView(picker, picker.views[index]);\n }\n\n function setupFooterButtons(picker) {\n while (picker.btnGroup.firstChild) {\n picker.btnGroup.removeChild(picker.btnGroup.firstChild);\n }\n\n // If there is only one view then we don't need view buttons\n if (picker.views.length === 1) {\n return;\n }\n\n for (var i = 0; i < picker.views.length; i++) {\n var button = util.el('a', 'btn btn-default');\n button.href = '#';\n button.setAttribute('data-index', i);\n var span = util.el('span', 'glyphicon glyphicon-' + picker.views[i].icon);\n button.appendChild(span);\n\n button.onclick = function (e) {\n e.preventDefault();\n viewClickHandler(picker, e);\n };\n\n picker.btnGroup.appendChild(button);\n }\n }\n\n function configurePicker(picker, inputGroup) {\n picker.currentInput = inputGroup.children[0];\n\n switch (picker.currentInput.getAttribute('data-type')) {\n case 'date':\n picker.views = [\n picker.dateView,\n ];\n break;\n\n case 'time':\n picker.views = [\n picker.timeView,\n ];\n break;\n\n default:\n picker.views = [\n picker.dateView,\n picker.timeView,\n ];\n }\n\n setupFooterButtons(picker);\n renderView(picker, picker.views[0]);\n }\n\n function createPopover(picker) {\n var popover = util.el('div', 'popover bottom datetime-popover');\n var arrow = util.el('div', 'arrow');\n var title = util.el('div', 'popover-title text-center');\n var body = util.el('div', 'popover-content');\n var footer = util.el('div', 'panel-footer');\n picker.btnGroup = util.el('div', 'btn-group btn-group-xs pull-right');\n var clearfix = util.el('div', 'clearfix');\n\n footer.appendChild(picker.btnGroup);\n footer.appendChild(clearfix);\n popover.appendChild(arrow);\n popover.appendChild(title);\n popover.appendChild(body);\n popover.appendChild(footer);\n\n return popover;\n }\n\n function getInputs(bindTo) {\n // If bindTo is a string treat it as a query selector\n if (typeof bindTo === 'string') {\n return document.querySelectorAll(bindTo);\n }\n\n // If bindTo is a DOM element\n if (bindTo.hasOwnProperty('nodeType')) {\n return [bindTo];\n }\n\n // If bindTo is an array\n if (bindTo instanceof Array) {\n var inputs = [];\n\n for (var i = 0; i < bindTo.length; i++) {\n inputs = inputs.concat(getInputs(bindTo[i]));\n }\n\n return inputs;\n }\n\n // If bindTo is null then nothing to do\n if (bindTo === null) {\n return null;\n }\n\n throw 'Unknown type to bind bootstrap-datetime picker to';\n }\n\n function overrideDefaults(overrides) {\n var options = {\n dateFormat: 'YYYY-MM-DD',\n dateTimeFormat: 'YYYY-MM-DD HH:mm:ss',\n timeFormat: 'HH:mm:ss',\n };\n\n if (!overrides) {\n return options;\n }\n\n for (var key in overrides) {\n if (overrides.hasOwnProperty(key) && options.hasOwnProperty(key)) {\n options[key] = overrides[key];\n }\n }\n\n return options;\n }\n\n function pickerClickHandler(picker, e) {\n var inputGroup = e.currentTarget.parentNode;\n\n // If popover is already visible for this picker then hide it\n if (picker.popover.parentNode === inputGroup.parentNode && picker.popover.style.display === 'block') {\n picker.popover.style.display = 'none';\n return;\n }\n\n picker.currentView = 0;\n\n // If picker is not already configured for this input\n if (picker.popover.parentNode !== inputGroup.parentNode) {\n // Add picker to DOM for this input\n inputGroup.parentNode.insertBefore(picker.popover, inputGroup.nextSibling);\n }\n\n configurePicker(picker, inputGroup);\n\n // Make picker visible\n picker.popover.style.display = 'block';\n\n picker.currentDateTime = moment(inputGroup.children[0].value);\n\n if (!picker.currentDateTime || !picker.currentDateTime.isValid()) {\n picker.currentDateTime = moment();\n }\n\n picker.views[picker.currentView].update(picker.currentDateTime);\n }\n\n function triggerCallbacks(picker) {\n for (var i = 0; i < picker.callbacks.length; i++) {\n picker.callbacks[i](picker.currentDateTime, picker.currentInput);\n }\n }\n\n function updateCallback(picker, dateTime) {\n picker.currentDateTime = dateTime;\n\n // If current view is only view or last view then close popover\n if ((picker.views.length === 1 || picker.currentView === (picker.views.length - 1)) &&\n picker.views[picker.currentView].closeOnUpdate) {\n picker.popover.style.display = 'none';\n } else if (picker.currentView < (picker.views.length - 1)) {\n picker.currentView += 1;\n renderView(picker, picker.views[picker.currentView]);\n picker.views[picker.currentView].update(picker.currentDateTime);\n }\n\n var format;\n\n // Get text format for datetime based on input type\n switch (picker.currentInput.getAttribute('data-type')) {\n case 'date':\n format = picker.options.dateFormat;\n break;\n\n case 'time':\n format = picker.options.timeFormat;\n break;\n\n default:\n format = picker.options.dateTimeFormat;\n }\n\n // Check for custom format specific to input\n var customFormat = picker.currentInput.getAttribute('data-format');\n\n // If input specifies custom format use it instead\n if (customFormat) {\n format = customFormat;\n }\n\n picker.currentInput.value = picker.currentDateTime.format(format);\n\n triggerCallbacks(picker);\n }\n\n function Picker(options) {\n this.options = overrideDefaults(options);\n this.popover = createPopover(this);\n this.views = [];\n this.callbacks = [];\n\n var self = this;\n\n this.dateView = new DateView(function (dateTime) {\n updateCallback(self, dateTime);\n });\n\n this.timeView = new TimeView(function (dateTime) {\n updateCallback(self, dateTime);\n });\n }\n\n Picker.prototype.addCallback = function (callback) {\n this.callbacks.push(callback);\n };\n\n Picker.prototype.auto = function () {\n this.bind('input[type=\"date\"], input[type=\"datetime\"], input[type=\"time\"]');\n };\n\n Picker.prototype.bind = function (bindTo) {\n var inputs = getInputs(bindTo);\n var self = this;\n\n for (var i = 0; i < inputs.length; i++) {\n var icon,\n inputGroup;\n\n var input = inputs[i];\n\n // If input is not in an input group, put it inside an input group\n if (input.parentNode.className.indexOf('input-group') < 0) {\n inputGroup = util.el('div', 'input-group');\n input.parentNode.appendChild(inputGroup);\n inputGroup.appendChild(input);\n } else {\n inputGroup = input.parentNode;\n }\n\n switch (input.type) {\n case 'date':\n input.setAttribute('data-type', 'date');\n icon = 'calendar';\n break;\n\n case 'time':\n input.setAttribute('data-type', 'time');\n icon = 'time';\n break;\n\n default:\n input.setAttribute('data-type', 'datetime');\n icon = 'calendar';\n }\n\n // Change input type to text so browser doesn't try to implement its own picker\n input.type = 'text';\n\n //\n var inputGroupBtn = util.el('div', 'input-group-btn');\n inputGroup.appendChild(inputGroupBtn);\n\n var pickerBtn = util.el('button', 'btn btn-default');\n inputGroupBtn.appendChild(pickerBtn);\n\n inputGroupBtn.onclick = function (e) {\n e.preventDefault();\n pickerClickHandler(self, e);\n };\n\n var glyph = util.el('span', 'glyphicon glyphicon-' + icon);\n pickerBtn.appendChild(glyph);\n }\n };\n\n Picker.prototype.removeCallback = function (callback) {\n this.callbacks.remove(callback);\n };\n\n return Picker;\n});\n\n"]} \ No newline at end of file +{"version":3,"file":"main.js","sources":["util.js","date-view.js","time-view.js","main.js"],"names":[],"mappings":"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","sourcesContent":["define('bootstrap-datetime/util',[], function () {\n exports = {};\n\n exports.el = function (type, cls) {\n var el = document.createElement(type);\n el.className = cls;\n return el;\n };\n\n return exports;\n});\n\n","/**\n * @module DateView\n * @returns {DateView} picker view for dates\n */\ndefine('bootstrap-datetime/date-view',[\n 'moment',\n './util',\n], function (\n moment,\n util\n) {\n 'use strict';\n\n var localeText = {\n TODAY: 'Today',\n };\n\n function clearCalendar(dateView) {\n // Remove days from calendar\n while (dateView.tbody.firstChild) {\n dateView.tbody.removeChild(dateView.tbody.firstChild);\n }\n }\n\n function createButton(dataId, contents, clickHandler) {\n var button = util.el('a', 'btn btn-xs btn-default');\n button.href = '#';\n button.setAttribute('data-id', dataId);\n button.innerHTML = contents;\n button.onclick = clickHandler;\n\n return button;\n }\n\n function createCalendar(dateView) {\n var th;\n var table = util.el('table', 'table table-condensed table-striped');\n var thead = util.el('thead');\n var theadTr = util.el('tr');\n dateView.tbody = util.el('tbody');\n\n table.appendChild(thead);\n thead.appendChild(theadTr);\n table.appendChild(dateView.tbody);\n\n var weekdays = moment.weekdaysShort();\n\n for (var i = 0; i < weekdays.length; i++) {\n th = util.el('th');\n th.innerHTML = weekdays[i];\n theadTr.appendChild(th);\n }\n\n return table;\n }\n\n function dayClickHandler(dateView, e) {\n e.preventDefault();\n\n // Update current datetime to be current visible month and year\n dateView.dt = dateView.visibleDateTime;\n\n // Update current datetime to be date clicked\n dateView.dt.date(parseInt(e.currentTarget.innerHTML));\n\n dateView.updateCallback(dateView.dt);\n }\n\n function updateHeader(dateView, dateTime) {\n dateView.header.innerHTML = moment.months()[dateTime.month()] + ' ' + dateTime.year();\n }\n\n function updateUI(dateView, dateTime) {\n dateView.visibleDateTime = moment(dateTime);\n\n updateHeader(dateView, dateTime);\n clearCalendar(dateView);\n\n var tr = util.el('tr');\n dateView.tbody.appendChild(tr);\n\n var dayCount,\n i,\n link,\n td;\n\n var firstOfMonth = moment(dateTime).startOf('month').day();\n var lastOfMonth = moment(dateTime).endOf('month');\n\n for (dayCount = 0; dayCount < firstOfMonth; dayCount++) {\n tr.appendChild(util.el('td'));\n }\n\n var currentMonthAndYear = dateView.dt.month() === dateView.visibleDateTime.month() &&\n dateView.dt.year() === dateView.visibleDateTime.year();\n\n for (i = 0 ; i < lastOfMonth.date(); i++) {\n if (dayCount === 7) {\n tr = util.el('tr');\n dateView.tbody.appendChild(tr);\n dayCount = 0;\n }\n\n td = util.el('td');\n link = util.el('a');\n link.href = '#';\n link.innerHTML = i + 1;\n link.onclick = function (e) {\n dayClickHandler(dateView, e);\n };\n\n if (currentMonthAndYear && (i + 1) === dateTime.date()) {\n link.className = 'btn btn-xs btn-default active';\n }\n\n td.appendChild(link);\n tr.appendChild(td);\n\n dayCount++;\n }\n\n for (i = lastOfMonth.day(); i < 6; i++) {\n tr.appendChild(util.el('td'));\n dayCount++;\n }\n }\n\n function nextMonthClickHandler(dateView) {\n updateUI(dateView, dateView.visibleDateTime.add(1, 'months'));\n }\n\n function previousMonthClickHandler(dateView) {\n updateUI(dateView, dateView.visibleDateTime.subtract(1, 'months'));\n }\n\n function todayClickHandler(dateView) {\n var now = moment();\n\n // If input already has a DateTime update time (keeping date the same)\n if (dateView.dt && dateView.dt.isValid()) {\n dateView.dt.date(now.date());\n dateView.dt.month(now.month());\n dateView.dt.year(now.year());\n // Otherwise set date and time to now\n } else {\n dateView.dt = now;\n }\n\n dateView.updateCallback(dateView.dt);\n }\n\n function DateView(updateCallback) {\n var self = this;\n\n this.footerButton = createButton('today-btn', localeText.TODAY, function (e) {\n e.preventDefault();\n todayClickHandler(self);\n });\n this.icon = 'calendar';\n this.updateCallback = updateCallback;\n this.closeOnUpdate = true;\n\n this.header = util.el('h3', 'panel-title');\n\n this.titleContents = [\n createButton('previous-btn', '', function (e) {\n e.preventDefault();\n previousMonthClickHandler(self);\n }),\n this.header,\n createButton('next-btn', '', function (e) {\n e.preventDefault();\n nextMonthClickHandler(self);\n }),\n ];\n\n this.bodyContents = [\n createCalendar(self),\n ];\n\n this.bodyDataId = 'date-content';\n }\n\n DateView.prototype.update = function (dateTime) {\n this.dt = dateTime;\n\n updateUI(this, this.dt);\n };\n\n return DateView;\n});\n\n","/**\n * @module TimeView\n * @returns {TimeView} picker view for times\n */\ndefine('bootstrap-datetime/time-view',[\n 'moment',\n './util',\n], function (\n moment,\n util\n) {\n 'use strict';\n\n var localeText = {\n DONE: 'Done',\n NOW: 'Now',\n };\n\n function createButton(timeView, dataId, additionalClassName, contents, clickHandler) {\n var button = util.el('a', 'btn btn-default');\n button.href = '#';\n\n if (additionalClassName) {\n button.className += ' ' + additionalClassName;\n }\n\n button.setAttribute('data-id', dataId);\n button.innerHTML = contents;\n button.onclick = function (e) {\n e.preventDefault();\n clickHandler(timeView, e);\n };\n\n return button;\n }\n\n function updateTime(timeView) {\n if (!timeView.dt || !timeView.dt.isValid()) {\n timeView.dt = moment();\n }\n\n timeView.dt.hour(timeView.hourInput.value);\n timeView.dt.minute(timeView.minuteInput.value);\n timeView.dt.second(timeView.secondInput.value);\n\n timeView.updateCallback(timeView.dt);\n }\n\n function doneClickHandler(timeView) {\n timeView.closeOnUpdate = true;\n timeView.updateCallback(timeView.dt);\n timeView.closeOnUpdate = false;\n }\n\n function downClickHandler(timeView, e) {\n var btn = e.currentTarget;\n var input = null;\n var max = 59;\n\n switch (btn.getAttribute('data-id')) {\n case 'hour-down-btn':\n input = timeView.hourInput;\n max = 23;\n break;\n\n case 'minute-down-btn':\n input = timeView.minuteInput;\n break;\n\n default: // second-down-btn\n input = timeView.secondInput;\n }\n\n var val = parseInt(input.value);\n\n if (isNaN(val) || val === 0) {\n input.value = max;\n } else {\n input.value = --val;\n }\n\n updateTime(timeView);\n }\n\n function upClickHandler(timeView, e) {\n var btn = e.currentTarget;\n var input = null;\n var max = 59;\n\n switch (btn.getAttribute('data-id')) {\n case 'hour-up-btn':\n input = timeView.hourInput;\n max = 23;\n break;\n\n case 'minute-up-btn':\n input = timeView.minuteInput;\n break;\n\n default: // second-up-btn\n input = timeView.secondInput;\n }\n\n var val = parseInt(input.value);\n\n if (isNaN(val) || val === max) {\n input.value = 0;\n } else {\n input.value = ++val;\n }\n\n updateTime(timeView);\n }\n\n function createNumericPicker(timeView, dataId) {\n var div = util.el('div', 'col-md-4 text-center');\n\n var upBtn = createButton(timeView, dataId + '-up-btn', '', '', upClickHandler);\n var downBtn = createButton(timeView, dataId + '-down-btn', '', '', downClickHandler);\n var input = util.el('input', 'form-control');\n input.maxLength = 2;\n input.setAttribute('data-id', dataId + '-input');\n\n div.appendChild(upBtn);\n div.appendChild(input);\n div.appendChild(downBtn);\n\n return div;\n }\n\n function nowClickHandler(timeView) {\n var now = moment();\n\n // If input already has a DateTime update date (keeping time the same)\n if (timeView.dt && timeView.dt.isValid()) {\n timeView.dt.hour(now.hour());\n timeView.dt.minute(now.minute());\n timeView.dt.second(now.second());\n // Otherwise set date and zero out time\n } else {\n timeView.dt = now;\n timeView.dt.hour(0);\n timeView.dt.minute(0);\n timeView.dt.second(0);\n }\n\n timeView.closeOnUpdate = true;\n timeView.updateCallback(timeView.dt);\n timeView.closeOnUpdate = false;\n }\n\n function updateUI(dateView, dateTime) {\n dateView.hourInput.value = dateTime.hour();\n dateView.minuteInput.value = dateTime.minute();\n dateView.secondInput.value = dateTime.second();\n }\n\n function TimeView(updateCallback) {\n this.icon = 'time';\n this.footerButton = createButton(this, 'now-btn', 'btn-xs', localeText.NOW, nowClickHandler);\n this.closeOnUpdate = false;\n\n var clearDiv = util.el('div', 'clearfix');\n\n var hourPicker = createNumericPicker(this, 'hour');\n var minutePicker = createNumericPicker(this, 'minute');\n var secondPicker = createNumericPicker(this, 'second');\n\n this.hourInput = hourPicker.children[1];\n this.minuteInput = minutePicker.children[1];\n this.secondInput = secondPicker.children[1];\n\n var doneBtn = util.el('a', 'btn btn-xs btn-default pull-right');\n doneBtn.href = '#';\n doneBtn.textContent = localeText.DONE;\n doneBtn.setAttribute('data-id', 'done-btn');\n\n var self = this;\n\n doneBtn.onclick = function (e) {\n e.preventDefault();\n doneClickHandler(self);\n };\n\n this.bodyContents = [\n hourPicker,\n minutePicker,\n secondPicker,\n doneBtn,\n clearDiv,\n ];\n\n this.titleContents = null;\n this.bodyDataId = 'time-content';\n this.updateCallback = updateCallback;\n }\n\n TimeView.prototype.update = function (datetime) {\n this.dt = datetime;\n\n updateUI(this, this.dt);\n };\n\n return TimeView;\n});\n\n","/**\n * @module main\n */\ndefine('bootstrap-datetime/main',[\n './date-view',\n 'moment',\n './time-view',\n './util',\n], function (\n DateView,\n moment,\n TimeView,\n util\n) {\n 'use strict';\n\n function addViewFooterBtn(picker) {\n while (picker.btnGroup.previousElementSibling) {\n picker.btnGroup.parentNode.removeChild(picker.btnGroup.previousElementSibling);\n }\n\n picker.btnGroup.parentNode.insertBefore(picker.views[picker.currentView].footerButton, picker.btnGroup);\n }\n\n function updateActiveViewBtn(picker) {\n var activeBtn = picker.btnGroup.querySelector('.active');\n\n if (activeBtn && activeBtn.className.indexOf('active')) {\n activeBtn.className = activeBtn.className.replace('active', '');\n }\n\n if (picker.btnGroup.children.length > picker.currentView) {\n var currentBtn = picker.btnGroup.children[picker.currentView];\n\n if (currentBtn.className.indexOf('active') < 0) {\n currentBtn.className += ' active';\n }\n }\n }\n\n function renderView(picker, view) {\n var i;\n var titleContents = view.titleContents;\n var titleDiv = picker.popover.children[1];\n var bodyContents = view.bodyContents;\n var bodyDiv = picker.popover.children[2];\n\n // Remove current children from popover title\n while (titleDiv.firstChild) {\n titleDiv.removeChild(titleDiv.firstChild);\n }\n\n // Remove current children from popover body\n while (bodyDiv.firstChild) {\n bodyDiv.removeChild(bodyDiv.firstChild);\n }\n\n if (titleContents) {\n // Add title contents from view\n for (i = 0; i < titleContents.length; i++) {\n titleDiv.appendChild(titleContents[i]);\n }\n\n titleDiv.style.display = 'block';\n } else {\n titleDiv.style.display = 'none';\n }\n\n if (bodyContents) {\n // Add title contents from view\n for (i = 0; i < bodyContents.length; i++) {\n bodyDiv.appendChild(bodyContents[i]);\n }\n\n bodyDiv.style.display = 'block';\n } else {\n bodyDiv.style.display = 'none';\n }\n\n bodyDiv.setAttribute('data-id', view.bodyDataId);\n\n updateActiveViewBtn(picker);\n addViewFooterBtn(picker);\n }\n\n function viewClickHandler(picker, e) {\n picker.currentInput = e.currentTarget;\n\n var index = parseInt(picker.currentInput.getAttribute('data-index'));\n\n // If clicked view is current view nothing to do\n if (index === picker.currentView) {\n return;\n }\n\n picker.currentView = index;\n\n renderView(picker, picker.views[index]);\n }\n\n function setupFooterButtons(picker) {\n while (picker.btnGroup.firstChild) {\n picker.btnGroup.removeChild(picker.btnGroup.firstChild);\n }\n\n // If there is only one view then we don't need view buttons\n if (picker.views.length === 1) {\n return;\n }\n\n for (var i = 0; i < picker.views.length; i++) {\n var button = util.el('a', 'btn btn-default');\n button.href = '#';\n button.setAttribute('data-index', i);\n var span = util.el('span', 'glyphicon glyphicon-' + picker.views[i].icon);\n button.appendChild(span);\n\n button.onclick = function (e) {\n e.preventDefault();\n viewClickHandler(picker, e);\n };\n\n picker.btnGroup.appendChild(button);\n }\n }\n\n function configurePicker(picker, inputGroup) {\n picker.currentInput = inputGroup.children[0];\n\n switch (picker.currentInput.getAttribute('data-type')) {\n case 'date':\n picker.views = [\n picker.dateView,\n ];\n break;\n\n case 'time':\n picker.views = [\n picker.timeView,\n ];\n break;\n\n default:\n picker.views = [\n picker.dateView,\n picker.timeView,\n ];\n }\n\n setupFooterButtons(picker);\n renderView(picker, picker.views[0]);\n }\n\n function createPopover(picker) {\n var popover = util.el('div', 'popover bottom datetime-popover');\n var arrow = util.el('div', 'arrow');\n var title = util.el('div', 'popover-title text-center');\n var body = util.el('div', 'popover-content');\n var footer = util.el('div', 'panel-footer');\n picker.btnGroup = util.el('div', 'btn-group btn-group-xs pull-right');\n var clearfix = util.el('div', 'clearfix');\n\n footer.appendChild(picker.btnGroup);\n footer.appendChild(clearfix);\n popover.appendChild(arrow);\n popover.appendChild(title);\n popover.appendChild(body);\n popover.appendChild(footer);\n\n return popover;\n }\n\n function getInputs(bindTo) {\n // If bindTo is a string treat it as a query selector\n if (typeof bindTo === 'string') {\n return document.querySelectorAll(bindTo);\n }\n\n // If bindTo is a DOM element\n if (bindTo.hasOwnProperty('nodeType')) {\n return [bindTo];\n }\n\n // If bindTo is an array\n if (bindTo instanceof Array) {\n var inputs = [];\n\n for (var i = 0; i < bindTo.length; i++) {\n inputs = inputs.concat(getInputs(bindTo[i]));\n }\n\n return inputs;\n }\n\n // If bindTo is null then nothing to do\n if (bindTo === null) {\n return null;\n }\n\n throw 'Unknown type to bind bootstrap-datetime picker to';\n }\n\n function overrideDefaults(overrides) {\n var options = {\n dateFormat: 'YYYY-MM-DD',\n dateTimeFormat: 'YYYY-MM-DD HH:mm:ss',\n timeFormat: 'HH:mm:ss',\n };\n\n if (!overrides) {\n return options;\n }\n\n for (var key in overrides) {\n if (overrides.hasOwnProperty(key) && options.hasOwnProperty(key)) {\n options[key] = overrides[key];\n }\n }\n\n return options;\n }\n\n function pickerClickHandler(picker, e) {\n var inputGroup = e.currentTarget.parentNode;\n\n // If popover is already visible for this picker then hide it\n if (picker.popover.parentNode === inputGroup.parentNode && picker.popover.style.display === 'block') {\n picker.popover.style.display = 'none';\n return;\n }\n\n picker.currentView = 0;\n\n // If picker is not already configured for this input\n if (picker.popover.parentNode !== inputGroup.parentNode) {\n // Add picker to DOM for this input\n inputGroup.parentNode.insertBefore(picker.popover, inputGroup.nextSibling);\n }\n\n configurePicker(picker, inputGroup);\n\n // Make picker visible\n picker.popover.style.display = 'block';\n\n picker.currentDateTime = moment(inputGroup.children[0].value);\n\n if (!picker.currentDateTime || !picker.currentDateTime.isValid()) {\n picker.currentDateTime = moment();\n }\n\n picker.views[picker.currentView].update(picker.currentDateTime);\n }\n\n function triggerCallbacks(picker) {\n for (var i = 0; i < picker.callbacks.length; i++) {\n picker.callbacks[i](picker.currentDateTime, picker.currentInput);\n }\n }\n\n function updateInput(picker, input, value) {\n var format;\n\n if (!value.isValid()) {\n input.value = '';\n return;\n }\n\n // Get text format for datetime based on input type\n switch (input.getAttribute('data-type')) {\n case 'date':\n format = picker.options.dateFormat;\n break;\n\n case 'time':\n format = picker.options.timeFormat;\n break;\n\n default:\n format = picker.options.dateTimeFormat;\n }\n\n // Check for custom format specific to input\n var customFormat = input.getAttribute('data-format');\n\n // If input specifies custom format use it instead\n if (customFormat) {\n format = customFormat;\n }\n\n input.value = value.format(format);\n }\n\n function updateCallback(picker, dateTime) {\n picker.currentDateTime = dateTime;\n\n // If current view is only view or last view then close popover\n if ((picker.views.length === 1 || picker.currentView === (picker.views.length - 1)) &&\n picker.views[picker.currentView].closeOnUpdate) {\n picker.popover.style.display = 'none';\n } else if (picker.currentView < (picker.views.length - 1)) {\n picker.currentView += 1;\n renderView(picker, picker.views[picker.currentView]);\n picker.views[picker.currentView].update(picker.currentDateTime);\n }\n\n updateInput(picker, picker.currentInput, picker.currentDateTime);\n\n triggerCallbacks(picker);\n }\n\n function Picker(options) {\n this.options = overrideDefaults(options);\n this.popover = createPopover(this);\n this.views = [];\n this.callbacks = [];\n\n var self = this;\n\n this.dateView = new DateView(function (dateTime) {\n updateCallback(self, dateTime);\n });\n\n this.timeView = new TimeView(function (dateTime) {\n updateCallback(self, dateTime);\n });\n }\n\n Picker.prototype.addCallback = function (callback) {\n this.callbacks.push(callback);\n };\n\n Picker.prototype.auto = function () {\n this.bind('input[type=\"date\"], input[type=\"datetime\"], input[type=\"time\"]');\n };\n\n Picker.prototype.bind = function (bindTo) {\n var inputs = getInputs(bindTo);\n var self = this;\n\n for (var i = 0; i < inputs.length; i++) {\n var icon,\n inputGroup;\n\n var input = inputs[i];\n\n // If input is not in an input group, put it inside an input group\n if (input.parentNode.className.indexOf('input-group') < 0) {\n inputGroup = util.el('div', 'input-group');\n input.parentNode.appendChild(inputGroup);\n inputGroup.appendChild(input);\n } else {\n inputGroup = input.parentNode;\n }\n\n switch (input.type) {\n case 'date':\n input.setAttribute('data-type', 'date');\n icon = 'calendar';\n break;\n\n case 'time':\n input.setAttribute('data-type', 'time');\n icon = 'time';\n break;\n\n default:\n input.setAttribute('data-type', 'datetime');\n icon = 'calendar';\n }\n\n // Change input type to text so browser doesn't try to implement its own picker\n input.type = 'text';\n\n //\n var inputGroupBtn = util.el('div', 'input-group-btn');\n inputGroup.appendChild(inputGroupBtn);\n\n var pickerBtn = util.el('button', 'btn btn-default');\n inputGroupBtn.appendChild(pickerBtn);\n\n inputGroupBtn.onclick = function (e) {\n e.preventDefault();\n pickerClickHandler(self, e);\n };\n\n var glyph = util.el('span', 'glyphicon glyphicon-' + icon);\n pickerBtn.appendChild(glyph);\n\n updateInput(this, input, moment(input.value));\n }\n };\n\n Picker.prototype.removeCallback = function (callback) {\n this.callbacks.remove(callback);\n };\n\n return Picker;\n});\n\n"]} \ No newline at end of file diff --git a/package.json b/package.json index f34c26f..9523b73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-datetime", - "version": "1.0.5", + "version": "1.0.6", "description": "Bootstrap datetime picker", "contributors": [ { diff --git a/src/js/bootstrap-datetime/main.js b/src/js/bootstrap-datetime/main.js index 2f68b61..06f9a97 100644 --- a/src/js/bootstrap-datetime/main.js +++ b/src/js/bootstrap-datetime/main.js @@ -257,23 +257,16 @@ define([ } } - function updateCallback(picker, dateTime) { - picker.currentDateTime = dateTime; + function updateInput(picker, input, value) { + var format; - // If current view is only view or last view then close popover - if ((picker.views.length === 1 || picker.currentView === (picker.views.length - 1)) && - picker.views[picker.currentView].closeOnUpdate) { - picker.popover.style.display = 'none'; - } else if (picker.currentView < (picker.views.length - 1)) { - picker.currentView += 1; - renderView(picker, picker.views[picker.currentView]); - picker.views[picker.currentView].update(picker.currentDateTime); + if (!value.isValid()) { + input.value = ''; + return; } - var format; - // Get text format for datetime based on input type - switch (picker.currentInput.getAttribute('data-type')) { + switch (input.getAttribute('data-type')) { case 'date': format = picker.options.dateFormat; break; @@ -287,14 +280,30 @@ define([ } // Check for custom format specific to input - var customFormat = picker.currentInput.getAttribute('data-format'); + var customFormat = input.getAttribute('data-format'); // If input specifies custom format use it instead if (customFormat) { format = customFormat; } - picker.currentInput.value = picker.currentDateTime.format(format); + input.value = value.format(format); + } + + function updateCallback(picker, dateTime) { + picker.currentDateTime = dateTime; + + // If current view is only view or last view then close popover + if ((picker.views.length === 1 || picker.currentView === (picker.views.length - 1)) && + picker.views[picker.currentView].closeOnUpdate) { + picker.popover.style.display = 'none'; + } else if (picker.currentView < (picker.views.length - 1)) { + picker.currentView += 1; + renderView(picker, picker.views[picker.currentView]); + picker.views[picker.currentView].update(picker.currentDateTime); + } + + updateInput(picker, picker.currentInput, picker.currentDateTime); triggerCallbacks(picker); } @@ -376,6 +385,8 @@ define([ var glyph = util.el('span', 'glyphicon glyphicon-' + icon); pickerBtn.appendChild(glyph); + + updateInput(this, input, moment(input.value)); } };