diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index be3aa17..a458795 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,5 +16,4 @@ //= require utils //= require moment //= require bootstrap-datetimepicker -//= require bootstrap-timepicker //= require jquery-date-format diff --git a/app/assets/javascripts/bootstrap-timepicker.js b/app/assets/javascripts/bootstrap-timepicker.js deleted file mode 100644 index 5972e3c..0000000 --- a/app/assets/javascripts/bootstrap-timepicker.js +++ /dev/null @@ -1,1097 +0,0 @@ -/*! - * Timepicker Component for Twitter Bootstrap - * - * Copyright 2013 Joris de Wit - * - * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -(function($, window, document, undefined) { - 'use strict'; - - // TIMEPICKER PUBLIC CLASS DEFINITION - var Timepicker = function(element, options) { - this.widget = ''; - this.$element = $(element); - this.defaultTime = options.defaultTime; - this.disableFocus = options.disableFocus; - this.disableMousewheel = options.disableMousewheel; - this.isOpen = options.isOpen; - this.minuteStep = options.minuteStep; - this.modalBackdrop = options.modalBackdrop; - this.orientation = options.orientation; - this.secondStep = options.secondStep; - this.showInputs = options.showInputs; - this.showMeridian = options.showMeridian; - this.showSeconds = options.showSeconds; - this.template = options.template; - this.appendWidgetTo = options.appendWidgetTo; - this.showWidgetOnAddonClick = options.showWidgetOnAddonClick; - - this._init(); - }; - - Timepicker.prototype = { - - constructor: Timepicker, - _init: function() { - var self = this; - - if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend'))) { - this.$element.parent('.input-append, .input-prepend').find('.add-on').on({ - 'click.timepicker': $.proxy(this.showWidget, this) - }); - this.$element.on({ - 'focus.timepicker': $.proxy(this.highlightUnit, this), - 'click.timepicker': $.proxy(this.highlightUnit, this), - 'keydown.timepicker': $.proxy(this.elementKeydown, this), - 'blur.timepicker': $.proxy(this.blurElement, this), - 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) - }); - } else { - if (this.template) { - this.$element.on({ - 'focus.timepicker': $.proxy(this.showWidget, this), - 'click.timepicker': $.proxy(this.showWidget, this), - 'blur.timepicker': $.proxy(this.blurElement, this), - 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) - }); - } else { - this.$element.on({ - 'focus.timepicker': $.proxy(this.highlightUnit, this), - 'click.timepicker': $.proxy(this.highlightUnit, this), - 'keydown.timepicker': $.proxy(this.elementKeydown, this), - 'blur.timepicker': $.proxy(this.blurElement, this), - 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this) - }); - } - } - - if (this.template !== false) { - this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this)); - } else { - this.$widget = false; - } - - if (this.showInputs && this.$widget !== false) { - this.$widget.find('input').each(function() { - $(this).on({ - 'click.timepicker': function() { $(this).select(); }, - 'keydown.timepicker': $.proxy(self.widgetKeydown, self), - 'keyup.timepicker': $.proxy(self.widgetKeyup, self) - }); - }); - } - - this.setDefaultTime(this.defaultTime); - }, - - blurElement: function() { - this.highlightedUnit = null; - this.updateFromElementVal(); - }, - - clear: function() { - this.hour = ''; - this.minute = ''; - this.second = ''; - this.meridian = ''; - - this.$element.val(''); - }, - - decrementHour: function() { - if (this.showMeridian) { - if (this.hour === 1) { - this.hour = 12; - } else if (this.hour === 12) { - this.hour--; - - return this.toggleMeridian(); - } else if (this.hour === 0) { - this.hour = 11; - - return this.toggleMeridian(); - } else { - this.hour--; - } - } else { - if (this.hour <= 0) { - this.hour = 23; - } else { - this.hour--; - } - } - }, - - decrementMinute: function(step) { - var newVal; - - if (step) { - newVal = this.minute - step; - } else { - newVal = this.minute - this.minuteStep; - } - - if (newVal < 0) { - this.decrementHour(); - this.minute = newVal + 60; - } else { - this.minute = newVal; - } - }, - - decrementSecond: function() { - var newVal = this.second - this.secondStep; - - if (newVal < 0) { - this.decrementMinute(true); - this.second = newVal + 60; - } else { - this.second = newVal; - } - }, - - elementKeydown: function(e) { - switch (e.keyCode) { - case 9: //tab - case 27: // escape - this.updateFromElementVal(); - break; - case 37: // left arrow - e.preventDefault(); - this.highlightPrevUnit(); - break; - case 38: // up arrow - e.preventDefault(); - switch (this.highlightedUnit) { - case 'hour': - this.incrementHour(); - this.highlightHour(); - break; - case 'minute': - this.incrementMinute(); - this.highlightMinute(); - break; - case 'second': - this.incrementSecond(); - this.highlightSecond(); - break; - case 'meridian': - this.toggleMeridian(); - this.highlightMeridian(); - break; - } - this.update(); - break; - case 39: // right arrow - e.preventDefault(); - this.highlightNextUnit(); - break; - case 40: // down arrow - e.preventDefault(); - switch (this.highlightedUnit) { - case 'hour': - this.decrementHour(); - this.highlightHour(); - break; - case 'minute': - this.decrementMinute(); - this.highlightMinute(); - break; - case 'second': - this.decrementSecond(); - this.highlightSecond(); - break; - case 'meridian': - this.toggleMeridian(); - this.highlightMeridian(); - break; - } - - this.update(); - break; - } - }, - - getCursorPosition: function() { - var input = this.$element.get(0); - - if ('selectionStart' in input) {// Standard-compliant browsers - - return input.selectionStart; - } else if (document.selection) {// IE fix - input.focus(); - var sel = document.selection.createRange(), - selLen = document.selection.createRange().text.length; - - sel.moveStart('character', - input.value.length); - - return sel.text.length - selLen; - } - }, - - getTemplate: function() { - var template, - hourTemplate, - minuteTemplate, - secondTemplate, - meridianTemplate, - templateContent; - - if (this.showInputs) { - hourTemplate = ''; - minuteTemplate = ''; - secondTemplate = ''; - meridianTemplate = ''; - } else { - hourTemplate = ''; - minuteTemplate = ''; - secondTemplate = ''; - meridianTemplate = ''; - } - - templateContent = ''+ - ''+ - ''+ - ''+ - ''+ - (this.showSeconds ? - ''+ - '' - : '') + - (this.showMeridian ? - ''+ - '' - : '') + - ''+ - ''+ - ' '+ - ''+ - ' '+ - (this.showSeconds ? - ''+ - '' - : '') + - (this.showMeridian ? - ''+ - '' - : '') + - ''+ - ''+ - ''+ - ''+ - ''+ - (this.showSeconds ? - ''+ - '' - : '') + - (this.showMeridian ? - ''+ - '' - : '') + - ''+ - '
   
'+ hourTemplate +':'+ minuteTemplate +':'+ secondTemplate +' '+ meridianTemplate +'
  
'; - - switch(this.template) { - case 'modal': - template = ''; - break; - case 'dropdown': - template = ''; - break; - } - - return template; - }, - - getTime: function() { - if (this.hour === '') { - return ''; - } - - return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : ''); - }, - - hideWidget: function() { - if (this.isOpen === false) { - return; - } - - this.$element.trigger({ - 'type': 'hide.timepicker', - 'time': { - 'value': this.getTime(), - 'hours': this.hour, - 'minutes': this.minute, - 'seconds': this.second, - 'meridian': this.meridian - } - }); - - if (this.template === 'modal' && this.$widget.modal) { - this.$widget.modal('hide'); - } else { - this.$widget.removeClass('open'); - } - - $(document).off('mousedown.timepicker, touchend.timepicker'); - - this.isOpen = false; - // show/hide approach taken by datepicker - this.$widget.detach(); - }, - - highlightUnit: function() { - this.position = this.getCursorPosition(); - if (this.position >= 0 && this.position <= 2) { - this.highlightHour(); - } else if (this.position >= 3 && this.position <= 5) { - this.highlightMinute(); - } else if (this.position >= 6 && this.position <= 8) { - if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMeridian(); - } - } else if (this.position >= 9 && this.position <= 11) { - this.highlightMeridian(); - } - }, - - highlightNextUnit: function() { - switch (this.highlightedUnit) { - case 'hour': - this.highlightMinute(); - break; - case 'minute': - if (this.showSeconds) { - this.highlightSecond(); - } else if (this.showMeridian){ - this.highlightMeridian(); - } else { - this.highlightHour(); - } - break; - case 'second': - if (this.showMeridian) { - this.highlightMeridian(); - } else { - this.highlightHour(); - } - break; - case 'meridian': - this.highlightHour(); - break; - } - }, - - highlightPrevUnit: function() { - switch (this.highlightedUnit) { - case 'hour': - if(this.showMeridian){ - this.highlightMeridian(); - } else if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMinute(); - } - break; - case 'minute': - this.highlightHour(); - break; - case 'second': - this.highlightMinute(); - break; - case 'meridian': - if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMinute(); - } - break; - } - }, - - highlightHour: function() { - var $element = this.$element.get(0), - self = this; - - this.highlightedUnit = 'hour'; - - if ($element.setSelectionRange) { - setTimeout(function() { - if (self.hour < 10) { - $element.setSelectionRange(0,1); - } else { - $element.setSelectionRange(0,2); - } - }, 0); - } - }, - - highlightMinute: function() { - var $element = this.$element.get(0), - self = this; - - this.highlightedUnit = 'minute'; - - if ($element.setSelectionRange) { - setTimeout(function() { - if (self.hour < 10) { - $element.setSelectionRange(2,4); - } else { - $element.setSelectionRange(3,5); - } - }, 0); - } - }, - - highlightSecond: function() { - var $element = this.$element.get(0), - self = this; - - this.highlightedUnit = 'second'; - - if ($element.setSelectionRange) { - setTimeout(function() { - if (self.hour < 10) { - $element.setSelectionRange(5,7); - } else { - $element.setSelectionRange(6,8); - } - }, 0); - } - }, - - highlightMeridian: function() { - var $element = this.$element.get(0), - self = this; - - this.highlightedUnit = 'meridian'; - - if ($element.setSelectionRange) { - if (this.showSeconds) { - setTimeout(function() { - if (self.hour < 10) { - $element.setSelectionRange(8,10); - } else { - $element.setSelectionRange(9,11); - } - }, 0); - } else { - setTimeout(function() { - if (self.hour < 10) { - $element.setSelectionRange(5,7); - } else { - $element.setSelectionRange(6,8); - } - }, 0); - } - } - }, - - incrementHour: function() { - if (this.showMeridian) { - if (this.hour === 11) { - this.hour++; - return this.toggleMeridian(); - } else if (this.hour === 12) { - this.hour = 0; - } - } - if (this.hour === 23) { - this.hour = 0; - - return; - } - this.hour++; - }, - - incrementMinute: function(step) { - var newVal; - - if (step) { - newVal = this.minute + step; - } else { - newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep); - } - - if (newVal > 59) { - this.incrementHour(); - this.minute = newVal - 60; - } else { - this.minute = newVal; - } - }, - - incrementSecond: function() { - var newVal = this.second + this.secondStep - (this.second % this.secondStep); - - if (newVal > 59) { - this.incrementMinute(true); - this.second = newVal - 60; - } else { - this.second = newVal; - } - }, - - mousewheel: function(e) { - if (this.disableMousewheel) { - return; - } - - e.preventDefault(); - e.stopPropagation(); - - var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail, - scrollTo = null; - - if (e.type === 'mousewheel') { - scrollTo = (e.originalEvent.wheelDelta * -1); - } - else if (e.type === 'DOMMouseScroll') { - scrollTo = 40 * e.originalEvent.detail; - } - - if (scrollTo) { - e.preventDefault(); - $(this).scrollTop(scrollTo + $(this).scrollTop()); - } - - switch (this.highlightedUnit) { - case 'minute': - if (delta > 0) { - this.incrementMinute(); - } else { - this.decrementMinute(); - } - this.highlightMinute(); - break; - case 'second': - if (delta > 0) { - this.incrementSecond(); - } else { - this.decrementSecond(); - } - this.highlightSecond(); - break; - case 'meridian': - this.toggleMeridian(); - this.highlightMeridian(); - break; - default: - if (delta > 0) { - this.incrementHour(); - } else { - this.decrementHour(); - } - this.highlightHour(); - break; - } - - return false; - }, - - // This method was adapted from bootstrap-datepicker. - place : function() { - if (this.isInline) { - return; - } - var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth = - $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop(); - - var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10; - var offset = this.component ? this.component.parent().offset() : this.$element.offset(); - var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false); - var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false); - var left = offset.left, top = offset.top; - - this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left'); - - if (this.orientation.x !== 'auto') { - this.picker.addClass('datepicker-orient-' + this.orientation.x); - if (this.orientation.x === 'right') { - left -= widgetWidth - width; - } - } else{ - // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways - // Default to left - this.$widget.addClass('timepicker-orient-left'); - if (offset.left < 0) { - left -= offset.left - visualPadding; - } else if (offset.left + widgetWidth > windowWidth) { - left = windowWidth - widgetWidth - visualPadding; - } - } - // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget - var yorient = this.orientation.y, topOverflow, bottomOverflow; - if (yorient === 'auto') { - topOverflow = -scrollTop + offset.top - widgetHeight; - bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight); - if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) { - yorient = 'top'; - } else { - yorient = 'bottom'; - } - } - this.$widget.addClass('timepicker-orient-' + yorient); - if (yorient === 'top'){ - top += height; - } else{ - top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10); - } - - this.$widget.css({ - top : top, - left : left, - zIndex : zIndex - }); - }, - - remove: function() { - $('document').off('.timepicker'); - if (this.$widget) { - this.$widget.remove(); - } - delete this.$element.data().timepicker; - }, - - setDefaultTime: function(defaultTime) { - if (!this.$element.val()) { - if (defaultTime === 'current') { - var dTime = new Date(), - hours = dTime.getHours(), - minutes = dTime.getMinutes(), - seconds = dTime.getSeconds(), - meridian = 'AM'; - - if (seconds !== 0) { - seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep; - if (seconds === 60) { - minutes += 1; - seconds = 0; - } - } - - if (minutes !== 0) { - minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep; - if (minutes === 60) { - hours += 1; - minutes = 0; - } - } - - if (this.showMeridian) { - if (hours === 0) { - hours = 12; - } else if (hours >= 12) { - if (hours > 12) { - hours = hours - 12; - } - meridian = 'PM'; - } else { - meridian = 'AM'; - } - } - - this.hour = hours; - this.minute = minutes; - this.second = seconds; - this.meridian = meridian; - - this.update(); - - } else if (defaultTime === false) { - this.hour = 0; - this.minute = 0; - this.second = 0; - this.meridian = 'AM'; - } else { - this.setTime(defaultTime); - } - } else { - this.updateFromElementVal(); - } - }, - - setTime: function(time, ignoreWidget) { - if (!time) { - this.clear(); - return; - } - - var timeArray, - hour, - minute, - second, - meridian; - - if (typeof time === 'object' && time.getMonth){ - // this is a date object - hour = time.getHours(); - minute = time.getMinutes(); - second = time.getSeconds(); - - if (this.showMeridian){ - meridian = 'AM'; - if (hour > 12){ - meridian = 'PM'; - hour = hour % 12; - } - - if (hour === 12){ - meridian = 'PM'; - } - } - } else { - if (time.match(/p/i) !== null) { - meridian = 'PM'; - } else { - meridian = 'AM'; - } - - time = time.replace(/[^0-9\:]/g, ''); - - timeArray = time.split(':'); - - hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString(); - minute = timeArray[1] ? timeArray[1].toString() : ''; - second = timeArray[2] ? timeArray[2].toString() : ''; - - // idiot proofing - if (hour.length > 4) { - second = hour.substr(4, 2); - } - if (hour.length > 2) { - minute = hour.substr(2, 2); - hour = hour.substr(0, 2); - } - if (minute.length > 2) { - second = minute.substr(2, 2); - minute = minute.substr(0, 2); - } - if (second.length > 2) { - second = second.substr(2, 2); - } - - hour = parseInt(hour, 10); - minute = parseInt(minute, 10); - second = parseInt(second, 10); - - if (isNaN(hour)) { - hour = 0; - } - if (isNaN(minute)) { - minute = 0; - } - if (isNaN(second)) { - second = 0; - } - - if (this.showMeridian) { - if (hour < 1) { - hour = 1; - } else if (hour > 12) { - hour = 12; - } - } else { - if (hour >= 24) { - hour = 23; - } else if (hour < 0) { - hour = 0; - } - if (hour < 13 && meridian === 'PM') { - hour = hour + 12; - } - } - - if (minute < 0) { - minute = 0; - } else if (minute >= 60) { - minute = 59; - } - - if (this.showSeconds) { - if (isNaN(second)) { - second = 0; - } else if (second < 0) { - second = 0; - } else if (second >= 60) { - second = 59; - } - } - } - - this.hour = hour; - this.minute = minute; - this.second = second; - this.meridian = meridian; - - this.update(ignoreWidget); - }, - - showWidget: function() { - if (this.isOpen) { - return; - } - - if (this.$element.is(':disabled')) { - return; - } - - // show/hide approach taken by datepicker - this.$widget.appendTo(this.appendWidgetTo); - var self = this; - $(document).on('mousedown.timepicker, touchend.timepicker', function (e) { - // This condition was inspired by bootstrap-datepicker. - // The element the timepicker is invoked on is the input but it has a sibling for addon/button. - if (!(self.$element.parent().find(e.target).length || - self.$widget.is(e.target) || - self.$widget.find(e.target).length)) { - self.hideWidget(); - } - }); - - this.$element.trigger({ - 'type': 'show.timepicker', - 'time': { - 'value': this.getTime(), - 'hours': this.hour, - 'minutes': this.minute, - 'seconds': this.second, - 'meridian': this.meridian - } - }); - - this.place(); - if (this.disableFocus) { - this.$element.blur(); - } - - // widget shouldn't be empty on open - if (this.hour === '') { - if (this.defaultTime) { - this.setDefaultTime(this.defaultTime); - } else { - this.setTime('0:0:0'); - } - } - - if (this.template === 'modal' && this.$widget.modal) { - this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this)); - } else { - if (this.isOpen === false) { - this.$widget.addClass('open'); - } - } - - this.isOpen = true; - }, - - toggleMeridian: function() { - this.meridian = this.meridian === 'AM' ? 'PM' : 'AM'; - }, - - update: function(ignoreWidget) { - this.updateElement(); - if (!ignoreWidget) { - this.updateWidget(); - } - - this.$element.trigger({ - 'type': 'changeTime.timepicker', - 'time': { - 'value': this.getTime(), - 'hours': this.hour, - 'minutes': this.minute, - 'seconds': this.second, - 'meridian': this.meridian - } - }); - }, - - updateElement: function() { - this.$element.val(this.getTime()).change(); - }, - - updateFromElementVal: function() { - this.setTime(this.$element.val()); - }, - - updateWidget: function() { - if (this.$widget === false) { - return; - } - - var hour = this.hour, - minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute, - second = this.second.toString().length === 1 ? '0' + this.second : this.second; - - if (this.showInputs) { - this.$widget.find('input.bootstrap-timepicker-hour').val(hour); - this.$widget.find('input.bootstrap-timepicker-minute').val(minute); - - if (this.showSeconds) { - this.$widget.find('input.bootstrap-timepicker-second').val(second); - } - if (this.showMeridian) { - this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian); - } - } else { - this.$widget.find('span.bootstrap-timepicker-hour').text(hour); - this.$widget.find('span.bootstrap-timepicker-minute').text(minute); - - if (this.showSeconds) { - this.$widget.find('span.bootstrap-timepicker-second').text(second); - } - if (this.showMeridian) { - this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian); - } - } - }, - - updateFromWidgetInputs: function() { - if (this.$widget === false) { - return; - } - - var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' + - this.$widget.find('input.bootstrap-timepicker-minute').val() + - (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') + - (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '') - ; - - this.setTime(t, true); - }, - - widgetClick: function(e) { - e.stopPropagation(); - e.preventDefault(); - - var $input = $(e.target), - action = $input.closest('a').data('action'); - - if (action) { - this[action](); - } - this.update(); - - if ($input.is('input')) { - $input.get(0).setSelectionRange(0,2); - } - }, - - widgetKeydown: function(e) { - var $input = $(e.target), - name = $input.attr('class').replace('bootstrap-timepicker-', ''); - - switch (e.keyCode) { - case 9: //tab - if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) { - return this.hideWidget(); - } - break; - case 27: // escape - this.hideWidget(); - break; - case 38: // up arrow - e.preventDefault(); - switch (name) { - case 'hour': - this.incrementHour(); - break; - case 'minute': - this.incrementMinute(); - break; - case 'second': - this.incrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.setTime(this.getTime()); - $input.get(0).setSelectionRange(0,2); - break; - case 40: // down arrow - e.preventDefault(); - switch (name) { - case 'hour': - this.decrementHour(); - break; - case 'minute': - this.decrementMinute(); - break; - case 'second': - this.decrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.setTime(this.getTime()); - $input.get(0).setSelectionRange(0,2); - break; - } - }, - - widgetKeyup: function(e) { - if ((e.keyCode === 65) || (e.keyCode === 77) || (e.keyCode === 80) || (e.keyCode === 46) || (e.keyCode === 8) || (e.keyCode >= 46 && e.keyCode <= 57)) { - this.updateFromWidgetInputs(); - } - } - }; - - //TIMEPICKER PLUGIN DEFINITION - $.fn.timepicker = function(option) { - var args = Array.apply(null, arguments); - args.shift(); - return this.each(function() { - var $this = $(this), - data = $this.data('timepicker'), - options = typeof option === 'object' && option; - - if (!data) { - $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data())))); - } - - if (typeof option === 'string') { - data[option].apply(data, args); - } - }); - }; - - $.fn.timepicker.defaults = { - defaultTime: 'current', - disableFocus: false, - disableMousewheel: false, - isOpen: false, - minuteStep: 15, - modalBackdrop: false, - orientation: { x: 'auto', y: 'auto'}, - secondStep: 15, - showSeconds: false, - showInputs: true, - showMeridian: true, - template: 'dropdown', - appendWidgetTo: 'body', - showWidgetOnAddonClick: true - }; - - $.fn.timepicker.Constructor = Timepicker; - -})(jQuery, window, document); diff --git a/app/assets/javascripts/time_entries.js b/app/assets/javascripts/time_entries.js index 518139f..28e10b2 100644 --- a/app/assets/javascripts/time_entries.js +++ b/app/assets/javascripts/time_entries.js @@ -1,77 +1,83 @@ -$(document).ready(function(){ +$(document).ready(function () { - $("#date_id").datetimepicker({format: 'MM/DD/YYYY'}) + var $date_input = $("#date_id"); + $date_input.datetimepicker({format: $date_input.data("format")}); - $("#start_time_id").timepicker(); - $("#end_time_id").timepicker(); + var $start_time_input = $("#start_time_id"); + var $end_time_input = $("#end_time_id"); + [$start_time_input, $end_time_input].forEach(function($x) { + $x.datetimepicker({format: $x.data("format"), stepping: 15}); + }) - $("#add_time_entry_submit").click(function(){ - date = $("#date_id").val(); - start_date = new Date(date + " " + $("#start_time_id").val()); - end_date = new Date(date + " " + $("#end_time_id").val()); + $("#add_time_entry_submit").click(function () { + date = $date_input.val(); + start_date = new Date(date + " " + $start_time_input.val()); + end_date = new Date(date + " " + $end_time_input.val()); - forward = $("#add_time_entry_submit").data("forward"); + forward = $("#add_time_entry_submit").data("forward"); - // If a bike is selected, forward to the bike - // checklist. - bike_id = parseInt($("#bike_id").val()); - if( bike_id > 0 ){ - forward = "/task_lists/" + bike_id + "/edit"; - } + // If a bike is selected, forward to the bike + // checklist. + bike_id = parseInt($("#bike_id").val()); + if (bike_id > 0) { + forward = "/task_lists/" + bike_id + "/edit"; + } - //FIXME: Ideally, we'd submit the dates as ISO, but I can't figure out - // how to get Netzke to render UTC dates correctly (it calls to_json - // somewhere and drops off the timezone). For the time being, save dates - // in locale like Netzke. - json_data = { time_entries: [{ - start_date: $.format.date(start_date, "dd-MM-yyyy hh:mm a"), - end_date: $.format.date(end_date, "dd-MM-yyyy hh:mm a"), - log_action_id: parseInt($('input[name=action_id]:checked').val()), - bike_id: bike_id, - description: $("#description_id").val(), - }]}; + //FIXME: Ideally, we'd submit the dates as ISO, but I can't figure out + // how to get Netzke to render UTC dates correctly (it calls to_json + // somewhere and drops off the timezone). For the time being, save dates + // in locale like Netzke. + json_data = { + time_entries: [{ + start_date: $.format.date(start_date, "dd-MM-yyyy hh:mm a"), + end_date: $.format.date(end_date, "dd-MM-yyyy hh:mm a"), + log_action_id: parseInt($('input[name=action_id]:checked').val()), + bike_id: bike_id, + description: $("#description_id").val(), + }] + }; - $.ajax({ - url: $("#add_time_entry_submit").data("url"), - type: "POST", - data: JSON.stringify(json_data), - contentType: 'application/json', - dataType: "json", - success: function(data, status, xhr){ - window.location = forward; - }, - error: function(data, status ){ - displayFormErrors(data.responseJSON); - } - }); + $.ajax({ + url: $("#add_time_entry_submit").data("url"), + type: "POST", + data: JSON.stringify(json_data), + contentType: 'application/json', + dataType: "json", + success: function (data, status, xhr) { + window.location = forward; + }, + error: function (data, status) { + displayFormErrors(data.responseJSON); + } + }); - }); + }); - $(".work_entry-delete-btn").click(function(){ - row = $(this).closest("tr"); - entry_id = row.data("id"); - start_date = row.data("start_date"); - duration = row.data("duration"); - description = row.data("description"); - $("#work_entry_start_date").html(start_date); - $("#work_entry_duration").html(duration); - $("#work_entry_description").html(description); - $("#confirmation_delete").data("entry_id", entry_id); - }); + $(".work_entry-delete-btn").click(function () { + row = $(this).closest("tr"); + entry_id = row.data("id"); + start_date = row.data("start_date"); + duration = row.data("duration"); + description = row.data("description"); + $("#work_entry_start_date").html(start_date); + $("#work_entry_duration").html(duration); + $("#work_entry_description").html(description); + $("#confirmation_delete").data("entry_id", entry_id); + }); - $("#confirmation_delete").click(function(){ - entry_id = $(this).data("entry_id"); - url = $("#confirmation_delete").data("url") + entry_id; - $.ajax({ - url: url, - type: "delete", - contentType: 'application/json', - success: function(data, status, xhr){ - location.reload(); - }, - error: function(data, status ){ - displayFormErrors(data.responseJSON); - } + $("#confirmation_delete").click(function () { + entry_id = $(this).data("entry_id"); + url = $("#confirmation_delete").data("url") + entry_id; + $.ajax({ + url: url, + type: "delete", + contentType: 'application/json', + success: function (data, status, xhr) { + location.reload(); + }, + error: function (data, status) { + displayFormErrors(data.responseJSON); + } + }); }); - }); }); diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index cb776d1..bf2198a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1,4 +1,3 @@ @import "bootstrap"; @import "bootstrap-datetimepicker"; -@import "bootstrap-timepicker"; @import "frontend"; diff --git a/app/assets/stylesheets/bootstrap-timepicker.css b/app/assets/stylesheets/bootstrap-timepicker.css deleted file mode 100644 index fa34752..0000000 --- a/app/assets/stylesheets/bootstrap-timepicker.css +++ /dev/null @@ -1,146 +0,0 @@ -/*! - * Timepicker Component for Twitter Bootstrap - * - * Copyright 2013 Joris de Wit - * - * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -.bootstrap-timepicker { - position: relative; -} -.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu { - left: auto; - right: 0; -} -.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before { - left: auto; - right: 12px; -} -.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after { - left: auto; - right: 13px; -} -.bootstrap-timepicker .add-on { - cursor: pointer; -} -.bootstrap-timepicker .add-on i { - display: inline-block; - width: 16px; - height: 16px; -} -.bootstrap-timepicker-widget.dropdown-menu { - padding: 4px; -} -.bootstrap-timepicker-widget.dropdown-menu.open { - display: inline-block; -} -.bootstrap-timepicker-widget.dropdown-menu:before { - border-bottom: 7px solid rgba(0, 0, 0, 0.2); - border-left: 7px solid transparent; - border-right: 7px solid transparent; - content: ""; - display: inline-block; - position: absolute; -} -.bootstrap-timepicker-widget.dropdown-menu:after { - border-bottom: 6px solid #FFFFFF; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - content: ""; - display: inline-block; - position: absolute; -} -.bootstrap-timepicker-widget.timepicker-orient-left:before { - left: 6px; -} -.bootstrap-timepicker-widget.timepicker-orient-left:after { - left: 7px; -} -.bootstrap-timepicker-widget.timepicker-orient-right:before { - right: 6px; -} -.bootstrap-timepicker-widget.timepicker-orient-right:after { - right: 7px; -} -.bootstrap-timepicker-widget.timepicker-orient-top:before { - top: -7px; -} -.bootstrap-timepicker-widget.timepicker-orient-top:after { - top: -6px; -} -.bootstrap-timepicker-widget.timepicker-orient-bottom:before { - bottom: -7px; - border-bottom: 0; - border-top: 7px solid #999; -} -.bootstrap-timepicker-widget.timepicker-orient-bottom:after { - bottom: -6px; - border-bottom: 0; - border-top: 6px solid #ffffff; -} -.bootstrap-timepicker-widget a.btn, -.bootstrap-timepicker-widget input { - border-radius: 4px; -} -.bootstrap-timepicker-widget table { - width: 100%; - margin: 0; -} -.bootstrap-timepicker-widget table td { - text-align: center; - height: 30px; - margin: 0; - padding: 2px; -} -.bootstrap-timepicker-widget table td:not(.separator) { - min-width: 30px; -} -.bootstrap-timepicker-widget table td span { - width: 100%; -} -.bootstrap-timepicker-widget table td a { - border: 1px transparent solid; - width: 100%; - display: inline-block; - margin: 0; - padding: 8px 0; - outline: 0; - color: #333; -} -.bootstrap-timepicker-widget table td a:hover { - text-decoration: none; - background-color: #eee; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - border-color: #ddd; -} -.bootstrap-timepicker-widget table td a i { - margin-top: 2px; - font-size: 18px; -} -.bootstrap-timepicker-widget table td input { - width: 25px; - margin: 0; - text-align: center; -} -.bootstrap-timepicker-widget .modal-content { - padding: 4px; -} -@media (min-width: 767px) { - .bootstrap-timepicker-widget.modal { - width: 200px; - margin-left: -100px; - } -} -@media (max-width: 767px) { - .bootstrap-timepicker { - width: 100%; - } - .bootstrap-timepicker .dropdown-menu { - width: 100%; - } -} diff --git a/app/assets/stylesheets/frontend.scss b/app/assets/stylesheets/frontend.scss index 95aba83..7ee3497 100644 --- a/app/assets/stylesheets/frontend.scss +++ b/app/assets/stylesheets/frontend.scss @@ -11,9 +11,45 @@ fieldset, .fieldset { margin-bottom: $line-height-computed; } -.bootstrap-timepicker { +.timepickers { .form-group { vertical-align: top; + &.dash { + line-height: 2.4em; + } + } + + .bootstrap-datetimepicker-widget.dropdown-menu { + width: auto; + } + + .bootstrap-datetimepicker-widget .timepicker-hour, + .bootstrap-datetimepicker-widget .timepicker-minute, + .bootstrap-datetimepicker-widget .timepicker-second { + width: 40px; + } + + .bootstrap-datetimepicker-widget table td { + height: 40px; + line-height: 40px; + width: 40px; + padding: 0 !important; + } + + .bootstrap-datetimepicker-widget table td.separator { + width: 10px; + } + + .bootstrap-datetimepicker-widget table td span { + width: 40px; + height: 40px; + line-height: 40px; + margin: 0; + } + + .bootstrap-datetimepicker-widget a[data-action] { + padding: 0; + color: #000; } } diff --git a/app/views/time_entries/new.haml b/app/views/time_entries/new.haml index 88629ce..f5580e5 100644 --- a/app/views/time_entries/new.haml +++ b/app/views/time_entries/new.haml @@ -1,27 +1,33 @@ = top_menu link_to_dashboard %h1 Add Time Entry +- time = Time.now +- date_format, time_format = '%m/%d/%Y', '%l:%M %p' +- mjs_date_format, mjs_time_format = 'MM/DD/YYYY', 'h:mm A' .row .col-xs-12.col-sm-6.col-lg-4 %fieldset .form-group.form-inline - = text_field_tag '', Date.today.strftime('%m/%d/%Y'), id: 'date_id', placeholder: 'Date', class: 'form-control', size: 12 + = text_field_tag nil, time.strftime(date_format), id: 'date_id', placeholder: 'Date', class: 'form-control', + size: 12, data: {format: mjs_date_format} .help-block - .form-group.bootstrap-timepicker.form-inline + .form-group.timepickers.form-inline .form-group %label.visible-xs Start time - = text_field_tag nil, nil, id: 'start_time_id', placeholder: 'Start time', class: 'form-control', size: 8 + = text_field_tag nil, time.strftime(time_format), id: 'start_time_id', placeholder: 'Start time', + class: 'form-control', size: 8, data: {format: mjs_time_format} .hidden#start_date .help-block - .form-group.hidden-xs + .form-group.dash.hidden-xs — .form-group %label.visible-xs End time - = text_field_tag nil, nil, id: 'end_time_id', placeholder: 'End time', class: 'form-control', size: 8 + = text_field_tag nil, time.strftime(time_format), id: 'end_time_id', placeholder: 'End time', + class: 'form-control', size: 8, data: {format: mjs_time_format} .hidden#end_date .help-block