diff --git a/app/assets/javascripts/datetimepicker.js b/app/assets/javascripts/datetimepicker.js new file mode 100644 index 00000000..cba600d9 --- /dev/null +++ b/app/assets/javascripts/datetimepicker.js @@ -0,0 +1,17 @@ +$(document).ready(function(){ + + $('.date_picker').datetimepicker({ + pickTime: false + }); + + $('.default_picker').datetimepicker(); + + $('.time_picker').datetimepicker({ + pickDate: false + }); + + $('.separated_picker div').on("changeDate",function(){ + $(this).siblings('input').val($(this).find('input').val() + ' ' + $(this).siblings('div').find('input').val()); + }); + +}); \ No newline at end of file diff --git a/app/assets/javascripts/lib/bootstrap-datetimepicker.js b/app/assets/javascripts/lib/bootstrap-datetimepicker.js new file mode 100644 index 00000000..0a24464d --- /dev/null +++ b/app/assets/javascripts/lib/bootstrap-datetimepicker.js @@ -0,0 +1,1156 @@ +/** + * @license + * ========================================================= + * bootstrap-datetimepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Contributions: + * - Andrew Rowls + * - Thiago de Arruda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= + */ + +(function($) { + + // Picker object + var smartPhone = (window.orientation != undefined); + var DateTimePicker = function(element, options) { + this.id = dpgId++; + this.init(element, options); + }; + + DateTimePicker.prototype = { + constructor: DateTimePicker, + + init: function(element, options) { + var icon; + if (!(options.pickTime || options.pickDate)) + throw new Error('Must choose at least one picker'); + this.options = options; + this.$element = $(element); + this.language = options.language in dates ? options.language : 'en' + this.pickDate = options.pickDate; + this.pickTime = options.pickTime; + this.isInput = this.$element.is('input'); + // this.component = this.$element.is('.input-prepend') ? this.$element.find('.add-on') : false; + this.component = this.$element.is('.input-append') ? this.$element.find('.add-on') : false; + this.format = options.format; + if (!this.format) { + if (this.isInput) this.format = this.$element.data('format'); + else this.format = this.$element.find('input').data('format'); + if (!this.format) this.format = 'MM/dd/yyyy'; + } + this._compileFormat(); + if (this.component) { + icon = this.component.find('i'); + } + if (this.pickTime) { + if (icon && icon.length) this.timeIcon = icon.data('time-icon'); + if (!this.timeIcon) this.timeIcon = 'icon-time'; + icon.addClass(this.timeIcon); + } + if (this.pickDate) { + if (icon && icon.length) this.dateIcon = icon.data('date-icon'); + if (!this.dateIcon) this.dateIcon = 'icon-calendar'; + icon.removeClass(this.timeIcon); + icon.addClass(this.dateIcon); + } + this.widget = $(getTemplate(this.timeIcon, options.pickDate, options.pickTime, options.pick12HourFormat)).appendTo('body'); + this.minViewMode = options.minViewMode||this.$element.data('date-minviewmode')||0; + if (typeof this.minViewMode === 'string') { + switch (this.minViewMode) { + case 'months': + this.minViewMode = 1; + break; + case 'years': + this.minViewMode = 2; + break; + default: + this.minViewMode = 0; + break; + } + } + this.viewMode = options.viewMode||this.$element.data('date-viewmode')||0; + if (typeof this.viewMode === 'string') { + switch (this.viewMode) { + case 'months': + this.viewMode = 1; + break; + case 'years': + this.viewMode = 2; + break; + default: + this.viewMode = 0; + break; + } + } + this.startViewMode = this.viewMode; + this.weekStart = options.weekStart||this.$element.data('date-weekstart')||0; + this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; + this.fillDow(); + this.fillMonths(); + this.fillHours(); + this.fillMinutes(); + this.fillSeconds(); + this.update(); + this.showMode(); + this._attachDatePickerEvents(); + }, + + show: function(e) { + this.widget.show(); + this.height = this.component ? this.component.outerHeight() : this.$element.outerHeight(); + this.width = this.component ? this.component.outerWidth() : this.$element.outerWidth(); + this.place(); + this.$element.trigger({ + type: 'show', + date: this._date + }); + this._attachDatePickerGlobalEvents(); + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + }, + + hide: function() { + // Ignore event if in the middle of a picker transition + var collapse = this.widget.find('.collapse') + for (var i = 0; i < collapse.length; i++) { + var collapseData = collapse.eq(i).data('collapse'); + if (collapseData && collapseData.transitioning) + return; + } + this.widget.hide(); + this.viewMode = this.startViewMode; + this.showMode(); + // this.set(); + this.$element.trigger({ + type: 'hide', + date: this._date + }); + this.actions.showPicker.call(this); + this._detachDatePickerGlobalEvents(); + }, + + set: function() { + var formatted = ''; + if (!this._unset) formatted = this.formatDate(this._date); + if (!this.isInput) { + if (this.component){ + var input = this.$element.find('input'); + input.val(formatted); + this._resetMaskPos(input); + } + this.$element.data('date', formatted); + } else { + this.$element.val(formatted); + this._resetMaskPos(this.$element); + } + }, + + setValue: function(newDate) { + if (!newDate) { + this._unset = true; + } else { + this._unset = false; + } + if (typeof newDate === 'string') { + this._date = this.parseDate(newDate); + } else { + this._date = new Date(newDate); + } + this.set(); + this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0); + this.fillDate(); + this.fillTime(); + }, + + getDate: function() { + if (this._unset) return null; + return new Date(this._date.valueOf()); + }, + + setDate: function(date) { + if (!date) this.setValue(null); + else this.setValue(date.valueOf()); + }, + + getLocalDate: function() { + if (this._unset) return null; + var d = this._date; + return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), + d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), d.getUTCMilliseconds()); + }, + + setLocalDate: function(localDate) { + if (!localDate) this.setValue(null); + else + this.setValue(Date.UTC( + localDate.getFullYear(), + localDate.getMonth(), + localDate.getDate(), + localDate.getHours(), + localDate.getMinutes(), + localDate.getSeconds(), + localDate.getMilliseconds())); + }, + + place: function(){ + var offset = this.component ? this.component.offset() : this.$element.offset(), + input = this.$element.find('input'); + this.widget.css({ + top: offset.top + this.height, + left: offset.left - input.outerWidth(), + }); + }, + + notifyChange: function(){ + this.$element.trigger({ + type: 'changeDate', + date: this.getDate(), + localDate: this.getLocalDate() + }); + }, + + update: function(newDate){ + var dateStr = newDate; + if (!dateStr) { + if (this.isInput) { + dateStr = this.$element.val(); + } else { + dateStr = this.$element.find('input').val(); + } + if (!dateStr) { + var tmp = new Date() + this._date = UTCDate(tmp.getFullYear(), + tmp.getMonth(), + tmp.getDate(), + tmp.getHours(), + tmp.getMinutes(), + tmp.getSeconds(), + tmp.getMilliseconds()) + } else { + this._date = this.parseDate(dateStr); + } + } + this.viewDate = UTCDate(this._date.getUTCFullYear(), this._date.getUTCMonth(), 1, 0, 0, 0, 0); + this.fillDate(); + this.fillTime(); + }, + + fillDow: function() { + var dowCnt = this.weekStart; + var html = ''; + while (dowCnt < this.weekStart + 7) { + html += '' + dates[this.language].daysMin[(dowCnt++) % 7] + ''; + } + html += ''; + this.widget.find('.datepicker-days thead').append(html); + }, + + fillMonths: function() { + var html = ''; + var i = 0 + while (i < 12) { + html += '' + dates[this.language].monthsShort[i++] + ''; + } + this.widget.find('.datepicker-months td').append(html); + }, + + fillDate: function() { + var year = this.viewDate.getUTCFullYear(); + var month = this.viewDate.getUTCMonth(); + var currentDate = UTCDate( + this._date.getUTCFullYear(), + this._date.getUTCMonth(), + this._date.getUTCDate(), + 0, 0, 0, 0 + ); + this.widget.find('.datepicker-days th:eq(1)').text( + dates[this.language].months[month] + ' ' + year); + var prevMonth = UTCDate(year, month-1, 28, 0, 0, 0, 0); + var day = DPGlobal.getDaysInMonth( + prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); + prevMonth.setUTCDate(day); + prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7); + var nextMonth = new Date(prevMonth.valueOf()); + nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName; + while (prevMonth.valueOf() < nextMonth) { + if (prevMonth.getUTCDay() === this.weekStart) { + html.push(''); + } + clsName = ''; + if (prevMonth.getUTCFullYear() < year || + (prevMonth.getUTCFullYear() == year && + prevMonth.getUTCMonth() < month)) { + clsName += ' old'; + } else if (prevMonth.getUTCFullYear() > year || + (prevMonth.getUTCFullYear() == year && + prevMonth.getUTCMonth() > month)) { + clsName += ' new'; + } + if (prevMonth.valueOf() === currentDate.valueOf()) { + clsName += ' active'; + } + html.push('' + prevMonth.getUTCDate() + ''); + if (prevMonth.getUTCDay() === this.weekEnd) { + html.push(''); + } + prevMonth.setUTCDate(prevMonth.getUTCDate() + 1); + } + this.widget.find('.datepicker-days tbody').empty().append(html.join('')); + var currentYear = this._date.getUTCFullYear(); + + var months = this.widget.find('.datepicker-months').find( + 'th:eq(1)').text(year).end().find('span').removeClass('active'); + if (currentYear === year) { + months.eq(this._date.getUTCMonth()).addClass('active'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.widget.find('.datepicker-years').find( + 'th:eq(1)').text(year + '-' + (year + 9)).end().find('td'); + year -= 1; + for (var i = -1; i < 11; i++) { + html += '' + year + ''; + year += 1; + } + yearCont.html(html); + }, + + fillHours: function() { + var table = this.widget.find( + '.timepicker .timepicker-hours table'); + table.parent().hide(); + var html = ''; + if (this.options.pick12HourFormat) { + var current = 1; + for (var i = 0; i < 3; i += 1) { + html += ''; + for (var j = 0; j < 4; j += 1) { + var c = current.toString(); + html += '' + padLeft(c, 2, '0') + ''; + current++; + } + html += '' + } + } else { + var current = 0; + for (var i = 0; i < 6; i += 1) { + html += ''; + for (var j = 0; j < 4; j += 1) { + var c = current.toString(); + html += '' + padLeft(c, 2, '0') + ''; + current++; + } + html += '' + } + } + table.html(html); + }, + + fillMinutes: function() { + var table = this.widget.find( + '.timepicker .timepicker-minutes table'); + table.parent().hide(); + var html = ''; + var current = 0; + for (var i = 0; i < 3; i++) { + html += ''; + for (var j = 0; j < 4; j += 1) { + var c = current.toString(); + html += '' + padLeft(c, 2, '0') + ''; + current += 5; + } + html += ''; + } + table.html(html); + }, + + fillSeconds: function() { + var table = this.widget.find( + '.timepicker .timepicker-seconds table'); + table.parent().hide(); + var html = ''; + var current = 0; + for (var i = 0; i < 5; i++) { + html += ''; + for (var j = 0; j < 4; j += 1) { + var c = current.toString(); + html += '' + padLeft(c, 2, '0') + ''; + current += 3; + } + html += ''; + } + table.html(html); + }, + + fillTime: function() { + if (!this._date) + return; + var timeComponents = this.widget.find('.timepicker span[data-time-component]'); + var table = timeComponents.closest('table'); + var is12HourFormat = this.options.pick12HourFormat; + var hour = this._date.getUTCHours(); + var period = 'AM'; + if (is12HourFormat) { + if (hour >= 12) period = 'PM'; + if (hour === 0) hour = 12; + else if (hour != 12) hour = hour % 12; + this.widget.find( + '.timepicker [data-action=togglePeriod]').text(period); + } + hour = padLeft(hour.toString(), 2, '0'); + var minute = padLeft(this._date.getUTCMinutes().toString(), 2, '0'); + var second = padLeft(this._date.getUTCSeconds().toString(), 2, '0'); + timeComponents.filter('[data-time-component=hours]').text(hour); + timeComponents.filter('[data-time-component=minutes]').text(minute); + timeComponents.filter('[data-time-component=seconds]').text(second); + }, + + click: function(e) { + e.stopPropagation(); + e.preventDefault(); + var target = $(e.target).closest('span, td, th'); + if (target.length === 1) { + switch(target[0].nodeName.toLowerCase()) { + case 'th': + switch(target[0].className) { + case 'switch': + this.showMode(1); + break; + case 'prev': + case 'next': + var vd = this.viewDate; + var navFnc = DPGlobal.modes[this.viewMode].navFnc; + var step = DPGlobal.modes[this.viewMode].navStep; + if (target[0].className === 'prev') step = step * -1; + vd['set' + navFnc](vd['get' + navFnc]() + step); + this.fillDate(); + this.set(); + break; + } + break; + case 'span': + if (target.is('.month')) { + var month = target.parent().find('span').index(target); + this.viewDate.setUTCMonth(month); + } else { + var year = parseInt(target.text(), 10) || 0; + this.viewDate.setUTCFullYear(year); + } + if (this.viewMode !== 0) { + this._date = UTCDate( + this.viewDate.getUTCFullYear(), + this.viewDate.getUTCMonth(), + this.viewDate.getUTCDate(), + this._date.getUTCHours(), + this._date.getUTCMinutes(), + this._date.getUTCSeconds(), + this._date.getUTCMilliseconds() + ); + this.notifyChange(); + } + this.showMode(-1); + this.fillDate(); + this.set(); + break; + case 'td': + if (target.is('.day')) { + var day = parseInt(target.text(), 10) || 1; + var month = this.viewDate.getUTCMonth(); + var year = this.viewDate.getUTCFullYear(); + if (target.is('.old')) { + if (month === 0) { + month = 11; + year -= 1; + } else { + month -= 1; + } + } else if (target.is('.new')) { + if (month == 11) { + month = 0; + year += 1; + } else { + month += 1; + } + } + this._date = UTCDate( + year, month, day, + this._date.getUTCHours(), + this._date.getUTCMinutes(), + this._date.getUTCSeconds(), + this._date.getUTCMilliseconds() + ); + this.viewDate = UTCDate( + year, month, Math.min(28, day) , 0, 0, 0, 0); + this.fillDate(); + this.set(); + this.notifyChange(); + this.widget.hide(); + } + break; + } + } + }, + + actions: { + incrementHours: function(e) { + this._date.setUTCHours(this._date.getUTCHours() + 1); + }, + + incrementMinutes: function(e) { + this._date.setUTCMinutes(this._date.getUTCMinutes() + 1); + }, + + // incrementSeconds: function(e) { + // this._date.setUTCSeconds(this._date.getUTCSeconds() + 1); + // }, + + decrementHours: function(e) { + this._date.setUTCHours(this._date.getUTCHours() - 1); + }, + + decrementMinutes: function(e) { + this._date.setUTCMinutes(this._date.getUTCMinutes() - 1); + }, + + // decrementSeconds: function(e) { + // this._date.setUTCSeconds(this._date.getUTCSeconds() - 1); + // }, + + togglePeriod: function(e) { + var hour = this._date.getUTCHours(); + if (hour >= 12) hour -= 12; + else hour += 12; + this._date.setUTCHours(hour); + }, + + showPicker: function() { + this.widget.find('.timepicker > div:not(.timepicker-picker)').hide(); + this.widget.find('.timepicker .timepicker-picker').show(); + }, + + showHours: function() { + this.widget.find('.timepicker .timepicker-picker').hide(); + this.widget.find('.timepicker .timepicker-hours').show(); + }, + + showMinutes: function() { + this.widget.find('.timepicker .timepicker-picker').hide(); + this.widget.find('.timepicker .timepicker-minutes').show(); + }, + + // showSeconds: function() { + // this.widget.find('.timepicker .timepicker-picker').hide(); + // this.widget.find('.timepicker .timepicker-seconds').show(); + // }, + + selectHour: function(e) { + var tgt = $(e.target); + var value = parseInt(tgt.text(), 10); + if (this.options.pick12HourFormat) { + var current = this._date.getUTCHours(); + if (current >= 12) { + if (value != 12) value = (value + 12) % 24; + } else { + if (value === 12) value = 0; + else value = value % 12; + } + } + this._date.setUTCHours(value); + this.actions.showPicker.call(this); + }, + + selectMinute: function(e) { + var tgt = $(e.target); + var value = parseInt(tgt.text(), 10); + this._date.setUTCMinutes(value); + this.actions.showPicker.call(this); + }, + + // selectSecond: function(e) { + // var tgt = $(e.target); + // var value = parseInt(tgt.text(), 10); + // this._date.setUTCSeconds(value); + // this.actions.showPicker.call(this); + // } + }, + + doAction: function(e) { + e.stopPropagation(); + e.preventDefault(); + if (!this._date) this._date = UTCDate(1970, 0, 0, 0, 0, 0, 0); + var action = $(e.currentTarget).data('action'); + var rv = this.actions[action].apply(this, arguments); + this.set(); + this.fillTime(); + this.notifyChange(); + return rv; + }, + + stopEvent: function(e) { + e.stopPropagation(); + e.preventDefault(); + }, + + // part of the following code was taken from + // http://cloud.github.com/downloads/digitalBush/jquery.maskedinput/jquery.maskedinput-1.3.js + keydown: function(e) { + var self = this, k = e.which, input = $(e.target); + if (k == 8 || k == 46) { + // backspace and delete cause the maskPosition + // to be recalculated + setTimeout(function() { + self._resetMaskPos(input); + }); + } + }, + + keypress: function(e) { + var k = e.which; + if (k == 8 || k == 46) { + // For those browsers which will trigger + // keypress on backspace/delete + return; + } + var input = $(e.target); + var c = String.fromCharCode(k); + var val = input.val() || ''; + val += c; + var mask = this._mask[this._maskPos]; + if (!mask) { + return false; + } + if (mask.end != val.length) { + return; + } + if (!mask.pattern.test(val.slice(mask.start))) { + val = val.slice(0, val.length - 1); + while ((mask = this._mask[this._maskPos]) && mask.character) { + val += mask.character; + // advance mask position past static + // part + this._maskPos++; + } + val += c; + if (mask.end != val.length) { + input.val(val); + return false; + } else { + if (!mask.pattern.test(val.slice(mask.start))) { + input.val(val.slice(0, mask.start)); + return false; + } else { + input.val(val); + this._maskPos++; + return false; + } + } + } else { + this._maskPos++; + } + }, + + change: function(e) { + var input = $(e.target); + var val = input.val(); + if (this._formatPattern.test(val)) { + this.update(); + this.setValue(this._date.getTime()); + this.notifyChange(); + this.set(); + } else if (val && val.trim()) { + this.setValue(this._date.getTime()); + if (this._date) this.set(); + else input.val(''); + } else { + if (this._date) { + this.setValue(null); + // unset the date when the input is + // erased + this.notifyChange(); + } + } + this._resetMaskPos(input); + }, + + showMode: function(dir) { + if (dir) { + this.viewMode = Math.max(this.minViewMode, Math.min( + 2, this.viewMode + dir)); + } + this.widget.find('.datepicker > div').hide().filter( + '.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + }, + + destroy: function() { + this._detachDatePickerEvents(); + this._detachDatePickerGlobalEvents(); + this.widget.remove(); + this.$element.removeData('datetimepicker'); + this.component.removeData('datetimepicker'); + }, + + formatDate: function(d) { + return this.format.replace(formatReplacer, function(match) { + var methodName, property, rv, len = match.length; + if (match === 'ms') + len = 1; + property = dateFormatComponents[match].property + if (property === 'Hours12') { + rv = d.getUTCHours(); + if (rv === 0) rv = 12; + else if (rv !== 12) rv = rv % 12; + } else if (property === 'Period12') { + if (d.getUTCHours() >= 12) return 'PM'; + else return 'AM'; + } else { + methodName = 'get' + property; + rv = d[methodName](); + } + if (methodName === 'getUTCMonth') rv = rv + 1; + if (methodName === 'getUTCYear') rv = rv + 1900 - 2000; + return padLeft(rv.toString(), len, '0'); + }); + }, + + parseDate: function(str) { + var match, i, property, methodName, value, parsed = {}; + if (!(match = this._formatPattern.exec(str))) + return null; + for (i = 1; i < match.length; i++) { + property = this._propertiesByIndex[i]; + if (!property) + continue; + value = match[i]; + if (/^\d+$/.test(value)) + value = parseInt(value, 10); + parsed[property] = value; + } + return this._finishParsingDate(parsed); + }, + + _resetMaskPos: function(input) { + var val = input.val(); + for (var i = 0; i < this._mask.length; i++) { + if (this._mask[i].end > val.length) { + // If the mask has ended then jump to + // the next + this._maskPos = i; + break; + } else if (this._mask[i].end === val.length) { + this._maskPos = i + 1; + break; + } + } + }, + + _finishParsingDate: function(parsed) { + var year, month, date, hours, minutes, seconds, milliseconds; + year = parsed.UTCFullYear; + if (parsed.UTCYear) year = 2000 + parsed.UTCYear; + if (!year) year = 1970; + if (parsed.UTCMonth) month = parsed.UTCMonth - 1; + else month = 0; + date = parsed.UTCDate || 1; + hours = parsed.UTCHours || 0; + minutes = parsed.UTCMinutes || 0; + seconds = parsed.UTCSeconds || 0; + milliseconds = parsed.UTCMilliseconds || 0; + if (parsed.Hours12) { + hours = parsed.Hours12; + } + if (parsed.Period12) { + if (/pm/i.test(parsed.Period12)) { + if (hours != 12) hours = (hours + 12) % 24; + } else { + hours = hours % 12; + } + } + return UTCDate(year, month, date, hours, minutes, seconds, milliseconds); + }, + + _compileFormat: function () { + var match, component, components = [], mask = [], + str = this.format, propertiesByIndex = {}, i = 0, pos = 0; + while (match = formatComponent.exec(str)) { + component = match[0]; + if (component in dateFormatComponents) { + i++; + propertiesByIndex[i] = dateFormatComponents[component].property; + components.push('\\s*' + dateFormatComponents[component].getPattern( + this) + '\\s*'); + mask.push({ + pattern: new RegExp(dateFormatComponents[component].getPattern( + this)), + property: dateFormatComponents[component].property, + start: pos, + end: pos += component.length + }); + } + else { + components.push(escapeRegExp(component)); + mask.push({ + pattern: new RegExp(escapeRegExp(component)), + character: component, + start: pos, + end: ++pos + }); + } + str = str.slice(component.length); + } + this._mask = mask; + this._maskPos = 0; + this._formatPattern = new RegExp( + '^\\s*' + components.join('') + '\\s*$'); + this._propertiesByIndex = propertiesByIndex; + }, + + _attachDatePickerEvents: function() { + var self = this; + // this handles date picker clicks + this.widget.on('click', '.datepicker *', $.proxy(this.click, this)); + // this handles time picker clicks + this.widget.on('click', '[data-action]', $.proxy(this.doAction, this)); + this.widget.on('mousedown', $.proxy(this.stopEvent, this)); + if (this.pickDate && this.pickTime) { + this.widget.on('click.togglePicker', '.accordion-toggle', function(e) { + e.stopPropagation(); + var $this = $(this); + var $parent = $this.closest('ul'); + var expanded = $parent.find('.collapse.in'); + var closed = $parent.find('.collapse:not(.in)'); + + if (expanded && expanded.length) { + var collapseData = expanded.data('collapse'); + if (collapseData && collapseData.transitioning) return; + expanded.collapse('hide'); + closed.collapse('show') + $this.find('i').toggleClass(self.timeIcon + ' ' + self.dateIcon); + self.$element.find('.add-on i').toggleClass(self.timeIcon + ' ' + self.dateIcon); + } + }); + } + if (this.isInput) { + this.$element.on({ + 'focus': $.proxy(this.show, this), + 'blur': $.proxy(this.hide, this), + 'change': $.proxy(this.change, this), + }); + if (this.options.maskInput) { + this.$element.on({ + 'keydown': $.proxy(this.keydown, this), + 'keypress': $.proxy(this.keypress, this) + }); + } + } else { + this.$element.on({ + 'focus': $.proxy(this.show, this), + 'blur': $.proxy(this.hide, this), + 'change': $.proxy(this.change, this), + }, 'input'); + if (this.options.maskInput) { + this.$element.on({ + 'keydown': $.proxy(this.keydown, this), + 'keypress': $.proxy(this.keypress, this) + }, 'input'); + } + if (this.component){ + this.component.on('click', $.proxy(this.show, this)); + } else { + this.$element.on('click', $.proxy(this.show, this)); + } + } + }, + + _attachDatePickerGlobalEvents: function() { + $(window).on( + 'resize.datetimepicker' + this.id, $.proxy(this.place, this)); + if (!this.isInput) { + $(document).on( + 'mousedown.datetimepicker' + this.id, $.proxy(this.hide, this)); + } + }, + + _detachDatePickerEvents: function() { + this.widget.off('click', '.datepicker *', this.click); + this.widget.off('click', '[data-action]'); + this.widget.off('mousedown', this.stopEvent); + if (this.pickDate && this.pickTime) { + this.widget.off('click.togglePicker'); + } + if (this.isInput) { + this.$element.off({ + 'focus': this.show, + 'change': this.change, + }); + if (this.options.maskInput) { + this.$element.off({ + 'keydown': this.keydown, + 'keypress': this.keypress + }); + } + } else { + this.$element.off({ + 'change': this.change, + }, 'input'); + if (this.options.maskInput) { + this.$element.off({ + 'keydown': this.keydown, + 'keypress': this.keypress + }, 'input'); + } + if (this.component){ + this.component.off('click', this.show); + } else { + this.$element.off('click', this.show); + } + } + }, + + _detachDatePickerGlobalEvents: function () { + $(window).off('resize.datetimepicker' + this.id); + if (!this.isInput) { + $(document).off('mousedown.datetimepicker' + this.id); + } + } + }; + + $.fn.datetimepicker = function ( option, val ) { + return this.each(function () { + var $this = $(this), + data = $this.data('datetimepicker'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('datetimepicker', (data = new DateTimePicker( + this, $.extend({}, $.fn.datetimepicker.defaults,options)))); + } + if (typeof option === 'string') data[option](val); + }); + }; + + $.fn.datetimepicker.defaults = { + maskInput: true, + pickDate: true, + pickTime: true, + pick12HourFormat: false + }; + $.fn.datetimepicker.Constructor = DateTimePicker; + var dpgId = 0; + var dates = $.fn.datetimepicker.dates = { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Aug", "Sep", "Oct", "Nov", "Dec"] + } + }; + + var dateFormatComponents = { + dd: {property: 'UTCDate', getPattern: function() { return '(0?[1-9]|[1-2][0-9]|3[0-1])\\b';}}, + MM: {property: 'UTCMonth', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}}, + yy: {property: 'UTCYear', getPattern: function() {return '(\\d{2})\\b'}}, + yyyy: {property: 'UTCFullYear', getPattern: function() {return '(\\d{4})\\b';}}, + hh: {property: 'UTCHours', getPattern: function() {return '(0?[0-9]|1[0-9]|2[0-3])\\b';}}, + mm: {property: 'UTCMinutes', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}}, + ss: {property: 'UTCSeconds', getPattern: function() {return '(0?[0-9]|[1-5][0-9])\\b';}}, + ms: {property: 'UTCMilliseconds', getPattern: function() {return '([0-9]{1,3})\\b';}}, + HH: {property: 'Hours12', getPattern: function() {return '(0?[1-9]|1[0-2])\\b';}}, + PP: {property: 'Period12', getPattern: function() {return '(AM|PM|am|pm|Am|aM|Pm|pM)\\b';}} + }; + + var keys = []; + for (var k in dateFormatComponents) keys.push(k); + keys[keys.length - 1] += '\\b'; + keys.push('.'); + + var formatComponent = new RegExp(keys.join('\\b|')); + keys.pop(); + var formatReplacer = new RegExp(keys.join('\\b|'), 'g'); + + function escapeRegExp(str) { + // http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + } + + function padLeft(s, l, c) { + if (l < s.length) return s; + else return Array(l - s.length + 1).join(c || ' ') + s; + } + + function getTemplate(timeIcon, pickDate, pickTime, is12Hours) { + if (pickDate && pickTime) { + return ( + '' + ); + } else if (pickTime) { + return ( + '' + ); + } else { + return ( + '' + ); + } + } + + function UTCDate() { + return new Date(Date.UTC.apply(Date, arguments)); + } + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'UTCMonth', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'UTCFullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'UTCFullYear', + navStep: 10 + }], + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] + }, + headTemplate: + '' + + '' + + '‹' + + '' + + '›' + + '' + + '', + contTemplate: '' + }; + DPGlobal.template = + '
' + + '' + + DPGlobal.headTemplate + + '' + + '
' + + '
' + + '
' + + '' + + DPGlobal.headTemplate + + DPGlobal.contTemplate+ + '
'+ + '
'+ + '
'+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + '
'+ + '
'; + var TPGlobal = { + hourTemplate: '', + minuteTemplate: '', + // secondTemplate: '', + }; + TPGlobal.getTemplate = function(is12Hours) { + return ( + '
' + + '' + + '' + + '' + + '' + + '' + + // '' + + // '' + + // (is12Hours ? '' : '') + + '' + + '' + + ' ' + + '' + + ' ' + + // '' + + // '' + + (is12Hours ? + '' + + '' : '') + + '' + + '' + + '' + + '' + + '' + + // '' + + // '' + + // (is12Hours ? '' : '') + + '' + + '
' + TPGlobal.hourTemplate + ':' + TPGlobal.minuteTemplate + ':' + TPGlobal.secondTemplate + '' + + '' + + '
' + + '
' + + '
' + + '' + + '
'+ + '
'+ + '
' + + '' + + '
'+ + // '
'+ + // '
' + + // '' + + // '
'+ + '
' + ); + } + + +})(window.jQuery) diff --git a/app/assets/javascripts/new_admin.js b/app/assets/javascripts/new_admin.js index 732eef1b..c5ec022e 100644 --- a/app/assets/javascripts/new_admin.js +++ b/app/assets/javascripts/new_admin.js @@ -19,4 +19,6 @@ //= require side_bar_history //= require rss //= require ajax_form -//= require inc/ajax_setting \ No newline at end of file +//= require inc/ajax_setting +//= require lib/bootstrap-datetimepicker +//= require datetimepicker \ No newline at end of file diff --git a/app/assets/stylesheets/lib/bootstrap-datetimepicker.css b/app/assets/stylesheets/lib/bootstrap-datetimepicker.css new file mode 100644 index 00000000..aaf685cb --- /dev/null +++ b/app/assets/stylesheets/lib/bootstrap-datetimepicker.css @@ -0,0 +1,221 @@ +/*! +* Datepicker for Bootstrap +* +* Copyright 2012 Stefan Petre +* Licensed under the Apache License v2.0 +* http://www.apache.org/licenses/LICENSE-2.0 +* +*/ +.clearfix { + *zoom:1; +} +.clearfix:before, +.clearfix:after { + display:table; + content:""; + line-height:0; +} +.clearfix:after { + clear:both; +} +.hide-text { + font:0/0 a; + color:transparent; + text-shadow:none; + background-color:transparent; + border:0; +} +.input-block-level { + display:block; + width:100%; + min-height:30px; + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; +} +.bootstrap-datetimepicker-widget { + top:0; + left:0; + min-width: 113px; + padding:4px; + margin-top:1px; + -webkit-border-radius:4px; + -moz-border-radius:4px; + border-radius:4px; +} +.bootstrap-datetimepicker-widget:before { + content:''; + display:inline-block; + border-left:7px solid transparent; + border-right:7px solid transparent; + border-bottom:7px solid #ccc; + border-bottom-color:rgba(0,0,0,0.2); + position:absolute; + top:-7px; + left:6px; +} +.bootstrap-datetimepicker-widget:after { + content:''; + display:inline-block; + border-left:6px solid transparent; + border-right:6px solid transparent; + border-bottom:6px solid #fff; + position:absolute; + top:-6px; + left:7px; +} +.bootstrap-datetimepicker-widget .timepicker { + min-width: 110px; +} +.bootstrap-datetimepicker-widget>ul { + list-style-type:none; + margin:0; +} +.bootstrap-datetimepicker-widget .timepicker-hour, +.bootstrap-datetimepicker-widget .timepicker-minute, +.bootstrap-datetimepicker-widget .timepicker-second { + font-weight:bold; + font-size:1.2em; +} +.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator { + width:4px; + padding:0; + margin:0; +} +.bootstrap-datetimepicker-widget .datepicker>div { + display:none; +} +.bootstrap-datetimepicker-widget .picker-switch { + text-align:center; +} +.bootstrap-datetimepicker-widget table { + width:100%; + margin:0; +} +.bootstrap-datetimepicker-widget td, +.bootstrap-datetimepicker-widget th { + text-align:center; + width:20px; + height:20px; + -webkit-border-radius:4px; + -moz-border-radius:4px; + border-radius:4px; + vertical-align: middle; +} +.bootstrap-datetimepicker-widget td.day:hover, +.bootstrap-datetimepicker-widget td.hour:hover, +.bootstrap-datetimepicker-widget td.minute:hover, +.bootstrap-datetimepicker-widget td.second:hover { + background:#eee; + cursor:pointer; +} +.bootstrap-datetimepicker-widget td.old, +.bootstrap-datetimepicker-widget td.new { + color:#999; +} +.bootstrap-datetimepicker-widget td.active, +.bootstrap-datetimepicker-widget td.active:hover { + color:#fff; + background-color:#006dcc; + background-image:-moz-linear-gradient(top,#08c,#04c); + background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c)); + background-image:-webkit-linear-gradient(top,#08c,#04c); + background-image:-o-linear-gradient(top,#08c,#04c); + background-image:linear-gradient(to bottom,#08c,#04c); + background-repeat:repeat-x; + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0); + border-color:#04c #04c #002a80; + border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25); + *background-color:#04c; + filter:progid:DXImageTransform.Microsoft.gradient(enabled = false); + color:#fff; + text-shadow:0 -1px 0 rgba(0,0,0,0.25); +} +.bootstrap-datetimepicker-widget td.active:hover, +.bootstrap-datetimepicker-widget td.active:hover:hover, +.bootstrap-datetimepicker-widget td.active:active, +.bootstrap-datetimepicker-widget td.active:hover:active, +.bootstrap-datetimepicker-widget td.active.active, +.bootstrap-datetimepicker-widget td.active:hover.active, +.bootstrap-datetimepicker-widget td.active.disabled, +.bootstrap-datetimepicker-widget td.active:hover.disabled, +.bootstrap-datetimepicker-widget td.active[disabled], +.bootstrap-datetimepicker-widget td.active:hover[disabled] { + color:#fff; + background-color:#04c; + *background-color:#003bb3; +} +.bootstrap-datetimepicker-widget td.active:active, +.bootstrap-datetimepicker-widget td.active:hover:active, +.bootstrap-datetimepicker-widget td.active.active, +.bootstrap-datetimepicker-widget td.active:hover.active { + background-color:#039 \9; +} +.bootstrap-datetimepicker-widget td span { + display:block; + width:100%; + height:54px; + line-height:54px; + float:left; + cursor:pointer; + -webkit-border-radius:4px; + -moz-border-radius:4px; + border-radius:4px; +} +.bootstrap-datetimepicker-widget .datepicker-months td span, +.bootstrap-datetimepicker-widget .datepicker-years td span { + width: 50px; +} +.bootstrap-datetimepicker-widget td span:hover { + background:#eee; +} +.bootstrap-datetimepicker-widget td span.active { + color:#fff; + background-color:#006dcc; + background-image:-moz-linear-gradient(top,#08c,#04c); + background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c)); + background-image:-webkit-linear-gradient(top,#08c,#04c); + background-image:-o-linear-gradient(top,#08c,#04c); + background-image:linear-gradient(to bottom,#08c,#04c); + background-repeat:repeat-x; + filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0); + border-color:#04c #04c #002a80; + border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25); + *background-color:#04c; + filter:progid:DXImageTransform.Microsoft.gradient(enabled = false); + color:#fff; + text-shadow:0 -1px 0 rgba(0,0,0,0.25); +} +.bootstrap-datetimepicker-widget td span.active:hover, +.bootstrap-datetimepicker-widget td span.active:active, +.bootstrap-datetimepicker-widget td span.active.active, +.bootstrap-datetimepicker-widget td span.active.disabled, +.bootstrap-datetimepicker-widget td span.active[disabled] { + color:#fff; + background-color:#04c; + *background-color:#003bb3; +} +.bootstrap-datetimepicker-widget td span.active:active, +.bootstrap-datetimepicker-widget td span.active.active { + background-color:#039 \9; +} +.bootstrap-datetimepicker-widget td span.old { + color:#999; +} +.bootstrap-datetimepicker-widget th.switch { + width:145px; +} +.bootstrap-datetimepicker-widget th.next, +.bootstrap-datetimepicker-widget th.prev { + font-size:21px; +} +.bootstrap-datetimepicker-widget thead tr:first-child th { + cursor:pointer; +} +.bootstrap-datetimepicker-widget thead tr:first-child th:hover { + background:#eee; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + cursor:pointer; +} diff --git a/app/assets/stylesheets/new_admin.css.erb b/app/assets/stylesheets/new_admin.css.erb index 2fb7e28e..494c760d 100644 --- a/app/assets/stylesheets/new_admin.css.erb +++ b/app/assets/stylesheets/new_admin.css.erb @@ -16,4 +16,5 @@ *= require isotope *= require icons *= require site-map + *= require lib/bootstrap-datetimepicker */ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dbd906ca..128fef23 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -12,7 +12,7 @@ class ApplicationController < ActionController::Base layout :layout_by_resource - helper :admin + helper :admin, :orbit_form before_filter :set_locale, :set_site, :prepare_for_mobile helper_attr :site_valid_locales diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e20a0c29..252ab78c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -254,6 +254,10 @@ module ApplicationHelper object.strftime("%Y-%m-%d") end + def display_time(object) + object.strftime("%H:%M") + end + def share_links(object, key) content_tag :div, :class => 'fb' do concat social_share_button_tag(object.title, :fb_url => generate_fb_url(object,key), :image => "http://#{request.env['HTTP_HOST']}#{object.image_url}") diff --git a/app/helpers/orbit_form_helper.rb b/app/helpers/orbit_form_helper.rb new file mode 100644 index 00000000..9dd6728f --- /dev/null +++ b/app/helpers/orbit_form_helper.rb @@ -0,0 +1,99 @@ +module OrbitFormHelper + def self.included(base) + ActionView::Helpers::FormBuilder.send(:include, Orbit::FormBuilder) + end + + def datetime_picker(object_name, method, options = {}) + options[:icon_time] ||= 'icons-clock' + options[:icon_date] ||= 'icons-calendar' + options[:input_class] ||= 'input-large' + options[:value] ||= options[:object][method] if options[:object] && options[:object][method] + case options[:picker_type] + when 'date' + content_tag :div, :id => options[:id], :class => options[:class] do + date_picker(object_name, method, options) + end + when 'time' + content_tag :div, :id => options[:id], :class => options[:class] do + time_picker(object_name, method, options) + end + when 'separated' + options[:label] ||= I18n.t('datetime_picker.separated.label') + content_tag :div, :id => options[:id], :class => "separated_picker #{options[:class]}" do + concat label_tag options[:label] unless options[:no_label] + concat hidden_field(object_name, method) + concat separated_picker(object_name, method, options) + end + else + content_tag :div, :id => options[:id], :class => options[:class] do + default_picker(object_name, method, options) + end + end + end + + def date_picker(object_name, method, options) + custom = {} + custom[:format] = 'yyyy-MM-dd' + custom[:value] = display_date(options[:value]) if options[:value] + custom[:picker_class] = 'date_picker' + custom[:label] = options[:label] || I18n.t('datetime_picker.date.label') + custom[:placeholder] = options[:placeholder] || I18n.t('datetime_picker.date.placeholder') + picker(object_name, method, options.merge(custom)) + end + + def default_picker(object_name, method, options) + custom = {} + custom[:format] = 'yyyy-MM-dd hh:mm' + custom[:value] = display_date_time(options[:value]) if options[:value] + custom[:picker_class] = 'default_picker' + custom[:label] = options[:label] || I18n.t('datetime_picker.default.label') + custom[:placeholder] = options[:placeholder] || I18n.t('datetime_picker.default.placeholder') + picker(object_name, method, options.merge(custom)) + end + + def time_picker(object_name, method, options) + custom = {} + custom[:format] = 'hh:mm' + custom[:value] = display_time(options[:value]) if options[:value] + custom[:picker_class] = 'time_picker' + custom[:label] = options[:label] || I18n.t('datetime_picker.time.label') + custom[:placeholder] = options[:placeholder] || I18n.t('datetime_picker.time.placeholder') + picker(object_name, method, options.merge(custom)) + end + + def separated_picker(object_name, method, options) + custom = {} + custom[:no_label] = true + date_picker(nil, nil, options.merge(custom)) + time_picker(nil, nil, options.merge(custom)) + end + + + def single_picker(object_name, method, options) + content_tag :div, :id => options[:id], :class => options[:class] do + picker(object_name, method, options) + end + end + + def double_picker(object_name, method, options) + + end + + def picker(object_name, method, options) + content_tag :div, :class => "#{options[:picker_class]} input-append" do + concat label_tag options[:label] unless options[:no_label] + concat text_field object_name, method, :placeholder => options[:placeholder], :class => options[:input_class], 'data-format' => options[:format], :value => options[:value] + concat (content_tag :span, :class => 'add-on' do + content_tag :i, nil, 'data-time-icon' => options[:icon_time], 'data-date-icon' => options[:icon_date] + end) + end + end + +end + +module Orbit::FormBuilder + # ActionPack's metaprogramming would have done this for us, if FormHelper#labeled_input + # had been defined at load. Instead we define it ourselves here. + def datetime_picker(method, options = {}) + @template.datetime_picker(@object_name, method, objectify_options(options)) + end +end \ No newline at end of file diff --git a/app/views/admin/ad_images/_form.html.erb b/app/views/admin/ad_images/_form.html.erb index fd139347..5277b312 100644 --- a/app/views/admin/ad_images/_form.html.erb +++ b/app/views/admin/ad_images/_form.html.erb @@ -1,13 +1,7 @@ -<% content_for :page_specific_css do %> - <%= stylesheet_link_tag "lib/datepicker" %> -<% end %> <% content_for :page_specific_javascript do %> - <%= javascript_include_tag "lib/datepicker" %> - <%= javascript_include_tag "lib/date.format.js" %> <%= javascript_include_tag "inc/modal-preview" %> <%= javascript_include_tag "/static/jquery.cycle.all.latest.js" %> <%= javascript_include_tag "inc/jquery.imagesloaded.js" %> - <% end %> @@ -21,51 +15,8 @@

<%= t(:date_) %>

-
-
- - <%= f.hidden_field :parse_post_date,:value => @ad_image.post_date.strftime('%Y / %m / %d') %> - <%= f.hidden_field :parse_unpost_date,:value => @ad_image.unpost_date.strftime('%Y / %m / %d')%> - -
-
-
-
- + <%= f.datetime_picker :post_date, :picker_type => 'date', :label => t(:start_date) %> + <%= f.datetime_picker :unpost_date, :picker_type => 'date', :label => t(:end_date) %>
diff --git a/config/locales/picker.en.yml b/config/locales/picker.en.yml new file mode 100644 index 00000000..999d9195 --- /dev/null +++ b/config/locales/picker.en.yml @@ -0,0 +1,14 @@ +en: + + datetime_picker: + date: + label: Date + placeholder: "YYYY-MM-DD" + default: + label: Date and time + placeholder: "YYYY-MM-DD HH:MM" + separated: + label: Date and time + time: + label: Time + placeholder: "HH:MM" \ No newline at end of file diff --git a/config/locales/picker.zh_tw.yml b/config/locales/picker.zh_tw.yml new file mode 100644 index 00000000..f92f47b0 --- /dev/null +++ b/config/locales/picker.zh_tw.yml @@ -0,0 +1,14 @@ +en: + + datetime_picker: + date: + label: 日期 + placeholder: "YYYY-MM-DD" + default: + label: 日期和時間 + placeholder: "YYYY-MM-DD HH:MM" + separated: + label: 日期和時間 + time: + label: 時間 + placeholder: "HH:MM" \ No newline at end of file diff --git a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_form.html.erb b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_form.html.erb index 77ac7c9e..e003f9cf 100644 --- a/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_form.html.erb +++ b/vendor/built_in_modules/announcement/app/views/panel/announcement/back_end/bulletins/_form.html.erb @@ -46,16 +46,10 @@

<%= t(:date_) %>

- -
- <%= f.datetime_select :postdate, {:use_month_numbers => true, :order => [:day, :month, :year] }, {:class => 'span1'} %> -
+ <%= f.datetime_picker :postdate, :picker_type => 'separated', :label => t(:start) %>
- -
- <%= f.datetime_select :deadline, {:use_month_numbers => true, :prompt => { :month => 'Month', :day => 'Day', :year => 'Year'}, :order => [:day, :month, :year] }, {:class => 'span1'} %> -
+ <%= f.datetime_picker :deadline, :picker_type => 'separated', :label => t(:end) %>