mirror of
				https://github.com/fspc/BikeShed-1.git
				synced 2025-10-31 08:55:36 -04:00 
			
		
		
		
	Added New Time Entry Front End
This commit is contained in:
		
							parent
							
								
									98b136e4f4
								
							
						
					
					
						commit
						80b2b7ff60
					
				| @ -14,3 +14,5 @@ | ||||
| //= require jquery_ujs
 | ||||
| //= require twitter/bootstrap/bootstrap-button
 | ||||
| //= require utils
 | ||||
| //= require bootstrap-datepicker
 | ||||
| //= require bootstrap-timepicker
 | ||||
|  | ||||
							
								
								
									
										474
									
								
								app/assets/javascripts/bootstrap-datepicker.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										474
									
								
								app/assets/javascripts/bootstrap-datepicker.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @ -0,0 +1,474 @@ | ||||
| /* ========================================================= | ||||
|  * bootstrap-datepicker.js  | ||||
|  * http://www.eyecon.ro/bootstrap-datepicker
 | ||||
|  * ========================================================= | ||||
|  * Copyright 2012 Stefan Petre | ||||
|  * | ||||
|  * 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 Datepicker = function(element, options){ | ||||
| 		this.element = $(element); | ||||
| 		this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); | ||||
| 		this.picker = $(DPGlobal.template) | ||||
| 							.appendTo('body') | ||||
| 							.on({ | ||||
| 								click: $.proxy(this.click, this)//,
 | ||||
| 								//mousedown: $.proxy(this.mousedown, this)
 | ||||
| 							}); | ||||
| 		this.isInput = this.element.is('input'); | ||||
| 		this.component = this.element.is('.date') ? this.element.find('.add-on') : false; | ||||
| 		 | ||||
| 		if (this.isInput) { | ||||
| 			this.element.on({ | ||||
| 				focus: $.proxy(this.show, this), | ||||
| 				//blur: $.proxy(this.hide, this),
 | ||||
| 				keyup: $.proxy(this.update, this) | ||||
| 			}); | ||||
| 		} else { | ||||
| 			if (this.component){ | ||||
| 				this.component.on('click', $.proxy(this.show, this)); | ||||
| 			} else { | ||||
| 				this.element.on('click', $.proxy(this.show, this)); | ||||
| 			} | ||||
| 		} | ||||
| 	 | ||||
| 		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.onRender = options.onRender; | ||||
| 		this.fillDow(); | ||||
| 		this.fillMonths(); | ||||
| 		this.update(); | ||||
| 		this.showMode(); | ||||
| 	}; | ||||
| 	 | ||||
| 	Datepicker.prototype = { | ||||
| 		constructor: Datepicker, | ||||
| 		 | ||||
| 		show: function(e) { | ||||
| 			this.picker.show(); | ||||
| 			this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); | ||||
| 			this.place(); | ||||
| 			$(window).on('resize', $.proxy(this.place, this)); | ||||
| 			if (e ) { | ||||
| 				e.stopPropagation(); | ||||
| 				e.preventDefault(); | ||||
| 			} | ||||
| 			if (!this.isInput) { | ||||
| 			} | ||||
| 			var that = this; | ||||
| 			$(document).on('mousedown', function(ev){ | ||||
| 				if ($(ev.target).closest('.datepicker').length == 0) { | ||||
| 					that.hide(); | ||||
| 				} | ||||
| 			}); | ||||
| 			this.element.trigger({ | ||||
| 				type: 'show', | ||||
| 				date: this.date | ||||
| 			}); | ||||
| 		}, | ||||
| 		 | ||||
| 		hide: function(){ | ||||
| 			this.picker.hide(); | ||||
| 			$(window).off('resize', this.place); | ||||
| 			this.viewMode = this.startViewMode; | ||||
| 			this.showMode(); | ||||
| 			if (!this.isInput) { | ||||
| 				$(document).off('mousedown', this.hide); | ||||
| 			} | ||||
| 			//this.set();
 | ||||
| 			this.element.trigger({ | ||||
| 				type: 'hide', | ||||
| 				date: this.date | ||||
| 			}); | ||||
| 		}, | ||||
| 		 | ||||
| 		set: function() { | ||||
| 			var formated = DPGlobal.formatDate(this.date, this.format); | ||||
| 			if (!this.isInput) { | ||||
| 				if (this.component){ | ||||
| 					this.element.find('input').prop('value', formated); | ||||
| 				} | ||||
| 				this.element.data('date', formated); | ||||
| 			} else { | ||||
| 				this.element.prop('value', formated); | ||||
| 			} | ||||
| 		}, | ||||
| 		 | ||||
| 		setValue: function(newDate) { | ||||
| 			if (typeof newDate === 'string') { | ||||
| 				this.date = DPGlobal.parseDate(newDate, this.format); | ||||
| 			} else { | ||||
| 				this.date = new Date(newDate); | ||||
| 			} | ||||
| 			this.set(); | ||||
| 			this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); | ||||
| 			this.fill(); | ||||
| 		}, | ||||
| 		 | ||||
| 		place: function(){ | ||||
| 			var offset = this.component ? this.component.offset() : this.element.offset(); | ||||
| 			this.picker.css({ | ||||
| 				top: offset.top + this.height, | ||||
| 				left: offset.left | ||||
| 			}); | ||||
| 		}, | ||||
| 		 | ||||
| 		update: function(newDate){ | ||||
| 			this.date = DPGlobal.parseDate( | ||||
| 				typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), | ||||
| 				this.format | ||||
| 			); | ||||
| 			this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); | ||||
| 			this.fill(); | ||||
| 		}, | ||||
| 		 | ||||
| 		fillDow: function(){ | ||||
| 			var dowCnt = this.weekStart; | ||||
| 			var html = '<tr>'; | ||||
| 			while (dowCnt < this.weekStart + 7) { | ||||
| 				html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>'; | ||||
| 			} | ||||
| 			html += '</tr>'; | ||||
| 			this.picker.find('.datepicker-days thead').append(html); | ||||
| 		}, | ||||
| 		 | ||||
| 		fillMonths: function(){ | ||||
| 			var html = ''; | ||||
| 			var i = 0 | ||||
| 			while (i < 12) { | ||||
| 				html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>'; | ||||
| 			} | ||||
| 			this.picker.find('.datepicker-months td').append(html); | ||||
| 		}, | ||||
| 		 | ||||
| 		fill: function() { | ||||
| 			var d = new Date(this.viewDate), | ||||
| 				year = d.getFullYear(), | ||||
| 				month = d.getMonth(), | ||||
| 				currentDate = this.date.valueOf(); | ||||
| 			this.picker.find('.datepicker-days th:eq(1)') | ||||
| 						.text(DPGlobal.dates.months[month]+' '+year); | ||||
| 			var prevMonth = new Date(year, month-1, 28,0,0,0,0), | ||||
| 				day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); | ||||
| 			prevMonth.setDate(day); | ||||
| 			prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); | ||||
| 			var nextMonth = new Date(prevMonth); | ||||
| 			nextMonth.setDate(nextMonth.getDate() + 42); | ||||
| 			nextMonth = nextMonth.valueOf(); | ||||
| 			var html = []; | ||||
| 			var clsName, | ||||
| 				prevY, | ||||
| 				prevM; | ||||
| 			while(prevMonth.valueOf() < nextMonth) { | ||||
| 				if (prevMonth.getDay() === this.weekStart) { | ||||
| 					html.push('<tr>'); | ||||
| 				} | ||||
| 				clsName = this.onRender(prevMonth); | ||||
| 				prevY = prevMonth.getFullYear(); | ||||
| 				prevM = prevMonth.getMonth(); | ||||
| 				if ((prevM < month &&  prevY === year) ||  prevY < year) { | ||||
| 					clsName += ' old'; | ||||
| 				} else if ((prevM > month && prevY === year) || prevY > year) { | ||||
| 					clsName += ' new'; | ||||
| 				} | ||||
| 				if (prevMonth.valueOf() === currentDate) { | ||||
| 					clsName += ' active'; | ||||
| 				} | ||||
| 				html.push('<td class="day '+clsName+'">'+prevMonth.getDate() + '</td>'); | ||||
| 				if (prevMonth.getDay() === this.weekEnd) { | ||||
| 					html.push('</tr>'); | ||||
| 				} | ||||
| 				prevMonth.setDate(prevMonth.getDate()+1); | ||||
| 			} | ||||
| 			this.picker.find('.datepicker-days tbody').empty().append(html.join('')); | ||||
| 			var currentYear = this.date.getFullYear(); | ||||
| 			 | ||||
| 			var months = this.picker.find('.datepicker-months') | ||||
| 						.find('th:eq(1)') | ||||
| 							.text(year) | ||||
| 							.end() | ||||
| 						.find('span').removeClass('active'); | ||||
| 			if (currentYear === year) { | ||||
| 				months.eq(this.date.getMonth()).addClass('active'); | ||||
| 			} | ||||
| 			 | ||||
| 			html = ''; | ||||
| 			year = parseInt(year/10, 10) * 10; | ||||
| 			var yearCont = this.picker.find('.datepicker-years') | ||||
| 								.find('th:eq(1)') | ||||
| 									.text(year + '-' + (year + 9)) | ||||
| 									.end() | ||||
| 								.find('td'); | ||||
| 			year -= 1; | ||||
| 			for (var i = -1; i < 11; i++) { | ||||
| 				html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>'; | ||||
| 				year += 1; | ||||
| 			} | ||||
| 			yearCont.html(html); | ||||
| 		}, | ||||
| 		 | ||||
| 		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': | ||||
| 								this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( | ||||
| 									this.viewDate, | ||||
| 									this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) +  | ||||
| 									DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) | ||||
| 								); | ||||
| 								this.fill(); | ||||
| 								this.set(); | ||||
| 								break; | ||||
| 						} | ||||
| 						break; | ||||
| 					case 'span': | ||||
| 						if (target.is('.month')) { | ||||
| 							var month = target.parent().find('span').index(target); | ||||
| 							this.viewDate.setMonth(month); | ||||
| 						} else { | ||||
| 							var year = parseInt(target.text(), 10)||0; | ||||
| 							this.viewDate.setFullYear(year); | ||||
| 						} | ||||
| 						if (this.viewMode !== 0) { | ||||
| 							this.date = new Date(this.viewDate); | ||||
| 							this.element.trigger({ | ||||
| 								type: 'changeDate', | ||||
| 								date: this.date, | ||||
| 								viewMode: DPGlobal.modes[this.viewMode].clsName | ||||
| 							}); | ||||
| 						} | ||||
| 						this.showMode(-1); | ||||
| 						this.fill(); | ||||
| 						this.set(); | ||||
| 						break; | ||||
| 					case 'td': | ||||
| 						if (target.is('.day') && !target.is('.disabled')){ | ||||
| 							var day = parseInt(target.text(), 10)||1; | ||||
| 							var month = this.viewDate.getMonth(); | ||||
| 							if (target.is('.old')) { | ||||
| 								month -= 1; | ||||
| 							} else if (target.is('.new')) { | ||||
| 								month += 1; | ||||
| 							} | ||||
| 							var year = this.viewDate.getFullYear(); | ||||
| 							this.date = new Date(year, month, day,0,0,0,0); | ||||
| 							this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); | ||||
| 							this.fill(); | ||||
| 							this.set(); | ||||
| 							this.element.trigger({ | ||||
| 								type: 'changeDate', | ||||
| 								date: this.date, | ||||
| 								viewMode: DPGlobal.modes[this.viewMode].clsName | ||||
| 							}); | ||||
| 						} | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		 | ||||
| 		mousedown: function(e){ | ||||
| 			e.stopPropagation(); | ||||
| 			e.preventDefault(); | ||||
| 		}, | ||||
| 		 | ||||
| 		showMode: function(dir) { | ||||
| 			if (dir) { | ||||
| 				this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); | ||||
| 			} | ||||
| 			this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); | ||||
| 		} | ||||
| 	}; | ||||
| 	 | ||||
| 	$.fn.datepicker = function ( option, val ) { | ||||
| 		return this.each(function () { | ||||
| 			var $this = $(this), | ||||
| 				data = $this.data('datepicker'), | ||||
| 				options = typeof option === 'object' && option; | ||||
| 			if (!data) { | ||||
| 				$this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); | ||||
| 			} | ||||
| 			if (typeof option === 'string') data[option](val); | ||||
| 		}); | ||||
| 	}; | ||||
| 
 | ||||
| 	$.fn.datepicker.defaults = { | ||||
| 		onRender: function(date) { | ||||
| 			return ''; | ||||
| 		} | ||||
| 	}; | ||||
| 	$.fn.datepicker.Constructor = Datepicker; | ||||
| 	 | ||||
| 	var DPGlobal = { | ||||
| 		modes: [ | ||||
| 			{ | ||||
| 				clsName: 'days', | ||||
| 				navFnc: 'Month', | ||||
| 				navStep: 1 | ||||
| 			}, | ||||
| 			{ | ||||
| 				clsName: 'months', | ||||
| 				navFnc: 'FullYear', | ||||
| 				navStep: 1 | ||||
| 			}, | ||||
| 			{ | ||||
| 				clsName: 'years', | ||||
| 				navFnc: 'FullYear', | ||||
| 				navStep: 10 | ||||
| 		}], | ||||
| 		dates:{ | ||||
| 			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"] | ||||
| 		}, | ||||
| 		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] | ||||
| 		}, | ||||
| 		parseFormat: function(format){ | ||||
| 			var separator = format.match(/[.\/\-\s].*?/), | ||||
| 				parts = format.split(/\W+/); | ||||
| 			if (!separator || !parts || parts.length === 0){ | ||||
| 				throw new Error("Invalid date format."); | ||||
| 			} | ||||
| 			return {separator: separator, parts: parts}; | ||||
| 		}, | ||||
| 		parseDate: function(date, format) { | ||||
| 			var parts = date.split(format.separator), | ||||
| 				date = new Date(), | ||||
| 				val; | ||||
| 			date.setHours(0); | ||||
| 			date.setMinutes(0); | ||||
| 			date.setSeconds(0); | ||||
| 			date.setMilliseconds(0); | ||||
| 			if (parts.length === format.parts.length) { | ||||
| 				var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); | ||||
| 				for (var i=0, cnt = format.parts.length; i < cnt; i++) { | ||||
| 					val = parseInt(parts[i], 10)||1; | ||||
| 					switch(format.parts[i]) { | ||||
| 						case 'dd': | ||||
| 						case 'd': | ||||
| 							day = val; | ||||
| 							date.setDate(val); | ||||
| 							break; | ||||
| 						case 'mm': | ||||
| 						case 'm': | ||||
| 							month = val - 1; | ||||
| 							date.setMonth(val - 1); | ||||
| 							break; | ||||
| 						case 'yy': | ||||
| 							year = 2000 + val; | ||||
| 							date.setFullYear(2000 + val); | ||||
| 							break; | ||||
| 						case 'yyyy': | ||||
| 							year = val; | ||||
| 							date.setFullYear(val); | ||||
| 							break; | ||||
| 					} | ||||
| 				} | ||||
| 				date = new Date(year, month, day, 0 ,0 ,0); | ||||
| 			} | ||||
| 			return date; | ||||
| 		}, | ||||
| 		formatDate: function(date, format){ | ||||
| 			var val = { | ||||
| 				d: date.getDate(), | ||||
| 				m: date.getMonth() + 1, | ||||
| 				yy: date.getFullYear().toString().substring(2), | ||||
| 				yyyy: date.getFullYear() | ||||
| 			}; | ||||
| 			val.dd = (val.d < 10 ? '0' : '') + val.d; | ||||
| 			val.mm = (val.m < 10 ? '0' : '') + val.m; | ||||
| 			var date = []; | ||||
| 			for (var i=0, cnt = format.parts.length; i < cnt; i++) { | ||||
| 				date.push(val[format.parts[i]]); | ||||
| 			} | ||||
| 			return date.join(format.separator); | ||||
| 		}, | ||||
| 		headTemplate: '<thead>'+ | ||||
| 							'<tr>'+ | ||||
| 								'<th class="prev">‹</th>'+ | ||||
| 								'<th colspan="5" class="switch"></th>'+ | ||||
| 								'<th class="next">›</th>'+ | ||||
| 							'</tr>'+ | ||||
| 						'</thead>', | ||||
| 		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>' | ||||
| 	}; | ||||
| 	DPGlobal.template = '<div class="datepicker dropdown-menu">'+ | ||||
| 							'<div class="datepicker-days">'+ | ||||
| 								'<table class=" table-condensed">'+ | ||||
| 									DPGlobal.headTemplate+ | ||||
| 									'<tbody></tbody>'+ | ||||
| 								'</table>'+ | ||||
| 							'</div>'+ | ||||
| 							'<div class="datepicker-months">'+ | ||||
| 								'<table class="table-condensed">'+ | ||||
| 									DPGlobal.headTemplate+ | ||||
| 									DPGlobal.contTemplate+ | ||||
| 								'</table>'+ | ||||
| 							'</div>'+ | ||||
| 							'<div class="datepicker-years">'+ | ||||
| 								'<table class="table-condensed">'+ | ||||
| 									DPGlobal.headTemplate+ | ||||
| 									DPGlobal.contTemplate+ | ||||
| 								'</table>'+ | ||||
| 							'</div>'+ | ||||
| 						'</div>'; | ||||
| 
 | ||||
| }( window.jQuery ); | ||||
							
								
								
									
										1097
									
								
								app/assets/javascripts/bootstrap-timepicker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1097
									
								
								app/assets/javascripts/bootstrap-timepicker.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								app/assets/javascripts/time_entries.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/assets/javascripts/time_entries.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| $(document).ready(function(){ | ||||
| 
 | ||||
| var currentdate = new Date(); | ||||
| $("#date_id").datepicker().on('changeDate', function(ev){ | ||||
|   $("#date_id").datepicker('hide'); | ||||
| }); | ||||
| $("#date_id").datepicker('setValue', currentdate); | ||||
| 
 | ||||
| $("#start_time_id").timepicker(); | ||||
| $("#end_time_id").timepicker(); | ||||
| }); | ||||
| @ -9,5 +9,7 @@ | ||||
|  * compiled file, but it's generally better to create a new file per style scope. | ||||
|  * | ||||
|  *= require_self | ||||
|  *= require datepicker | ||||
|  *= require bootstrap-timepicker | ||||
|  *= require bootstrap_and_overrides | ||||
| */ | ||||
|  | ||||
							
								
								
									
										146
									
								
								app/assets/stylesheets/bootstrap-timepicker.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								app/assets/stylesheets/bootstrap-timepicker.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | ||||
| /*! | ||||
|  * 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%; | ||||
|   } | ||||
| } | ||||
| @ -36,3 +36,7 @@ body { | ||||
| [data-toggle="buttons"] > .btn > input[type="checkbox"] { | ||||
|   display: none; | ||||
| } | ||||
| 
 | ||||
| .inline-block { | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
							
								
								
									
										182
									
								
								app/assets/stylesheets/datepicker.css
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										182
									
								
								app/assets/stylesheets/datepicker.css
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,182 @@ | ||||
| /*! | ||||
|  * Datepicker for Bootstrap | ||||
|  * | ||||
|  * Copyright 2012 Stefan Petre | ||||
|  * Licensed under the Apache License v2.0 | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  */ | ||||
| .datepicker { | ||||
|   top: 0; | ||||
|   left: 0; | ||||
|   padding: 4px; | ||||
|   margin-top: 1px; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
|   /*.dow { | ||||
|     border-top: 1px solid #ddd !important; | ||||
|   }*/ | ||||
| 
 | ||||
| } | ||||
| .datepicker: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; | ||||
| } | ||||
| .datepicker:after { | ||||
|   content: ''; | ||||
|   display: inline-block; | ||||
|   border-left: 6px solid transparent; | ||||
|   border-right: 6px solid transparent; | ||||
|   border-bottom: 6px solid #ffffff; | ||||
|   position: absolute; | ||||
|   top: -6px; | ||||
|   left: 7px; | ||||
| } | ||||
| .datepicker > div { | ||||
|   display: none; | ||||
| } | ||||
| .datepicker table { | ||||
|   width: 100%; | ||||
|   margin: 0; | ||||
| } | ||||
| .datepicker td, | ||||
| .datepicker th { | ||||
|   text-align: center; | ||||
|   width: 20px; | ||||
|   height: 20px; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| .datepicker td.day:hover { | ||||
|   background: #eeeeee; | ||||
|   cursor: pointer; | ||||
| } | ||||
| .datepicker td.day.disabled { | ||||
|   color: #eeeeee; | ||||
| } | ||||
| .datepicker td.old, | ||||
| .datepicker td.new { | ||||
|   color: #999999; | ||||
| } | ||||
| .datepicker td.active, | ||||
| .datepicker td.active:hover { | ||||
|   color: #ffffff; | ||||
|   background-color: #006dcc; | ||||
|   background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | ||||
|   background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -o-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: linear-gradient(to bottom, #0088cc, #0044cc); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); | ||||
|   border-color: #0044cc #0044cc #002a80; | ||||
|   border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | ||||
|   *background-color: #0044cc; | ||||
|   /* Darken IE7 buttons by default so they stand out more given they won't have borders */ | ||||
| 
 | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); | ||||
|   color: #fff; | ||||
|   text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | ||||
| } | ||||
| .datepicker td.active:hover, | ||||
| .datepicker td.active:hover:hover, | ||||
| .datepicker td.active:focus, | ||||
| .datepicker td.active:hover:focus, | ||||
| .datepicker td.active:active, | ||||
| .datepicker td.active:hover:active, | ||||
| .datepicker td.active.active, | ||||
| .datepicker td.active:hover.active, | ||||
| .datepicker td.active.disabled, | ||||
| .datepicker td.active:hover.disabled, | ||||
| .datepicker td.active[disabled], | ||||
| .datepicker td.active:hover[disabled] { | ||||
|   color: #ffffff; | ||||
|   background-color: #0044cc; | ||||
|   *background-color: #003bb3; | ||||
| } | ||||
| .datepicker td.active:active, | ||||
| .datepicker td.active:hover:active, | ||||
| .datepicker td.active.active, | ||||
| .datepicker td.active:hover.active { | ||||
|   background-color: #003399 \9; | ||||
| } | ||||
| .datepicker td span { | ||||
|   display: block; | ||||
|   width: 47px; | ||||
|   height: 54px; | ||||
|   line-height: 54px; | ||||
|   float: left; | ||||
|   margin: 2px; | ||||
|   cursor: pointer; | ||||
|   -webkit-border-radius: 4px; | ||||
|   -moz-border-radius: 4px; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| .datepicker td span:hover { | ||||
|   background: #eeeeee; | ||||
| } | ||||
| .datepicker td span.active { | ||||
|   color: #ffffff; | ||||
|   background-color: #006dcc; | ||||
|   background-image: -moz-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); | ||||
|   background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: -o-linear-gradient(top, #0088cc, #0044cc); | ||||
|   background-image: linear-gradient(to bottom, #0088cc, #0044cc); | ||||
|   background-repeat: repeat-x; | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); | ||||
|   border-color: #0044cc #0044cc #002a80; | ||||
|   border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); | ||||
|   *background-color: #0044cc; | ||||
|   /* Darken IE7 buttons by default so they stand out more given they won't have borders */ | ||||
| 
 | ||||
|   filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); | ||||
|   color: #fff; | ||||
|   text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | ||||
| } | ||||
| .datepicker td span.active:hover, | ||||
| .datepicker td span.active:focus, | ||||
| .datepicker td span.active:active, | ||||
| .datepicker td span.active.active, | ||||
| .datepicker td span.active.disabled, | ||||
| .datepicker td span.active[disabled] { | ||||
|   color: #ffffff; | ||||
|   background-color: #0044cc; | ||||
|   *background-color: #003bb3; | ||||
| } | ||||
| .datepicker td span.active:active, | ||||
| .datepicker td span.active.active { | ||||
|   background-color: #003399 \9; | ||||
| } | ||||
| .datepicker td span.old { | ||||
|   color: #999999; | ||||
| } | ||||
| .datepicker th.switch { | ||||
|   width: 145px; | ||||
| } | ||||
| .datepicker th.next, | ||||
| .datepicker th.prev { | ||||
|   font-size: 21px; | ||||
| } | ||||
| .datepicker thead tr:first-child th { | ||||
|   cursor: pointer; | ||||
| } | ||||
| .datepicker thead tr:first-child th:hover { | ||||
|   background: #eeeeee; | ||||
| } | ||||
| .input-append.date .add-on i, | ||||
| .input-prepend.date .add-on i { | ||||
|   display: block; | ||||
|   cursor: pointer; | ||||
|   width: 16px; | ||||
|   height: 16px; | ||||
| } | ||||
							
								
								
									
										10
									
								
								app/controllers/time_entries_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/controllers/time_entries_controller.rb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| class TimeEntriesController < AuthenticatedController | ||||
| 
 | ||||
|   def new | ||||
| 
 | ||||
|   end | ||||
| 
 | ||||
|   def index | ||||
| 
 | ||||
|   end | ||||
| end | ||||
| @ -4,7 +4,7 @@ | ||||
|     %meta{:charset => "utf-8"}/ | ||||
|     %title= content_for?(:title) ? yield(:title) : "Velocipede" | ||||
|     = csrf_meta_tags | ||||
|     = stylesheet_link_tag "bootstrap_and_overrides", :media => "all" | ||||
|     = stylesheet_link_tag "bootstrap_and_overrides", "datepicker", "bootstrap-timepicker", :media => "all" | ||||
|     /[if lt IE 9] | ||||
|       = javascript_include_tag "http://html5shim.googlecode.com/svn/trunk/html5.js" | ||||
|     :css | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| 
 | ||||
| %p | ||||
|   %p | ||||
|     %a{class: "btn btn-lg btn-block btn-primary"} Add Time Entry | ||||
|     %a{class: "btn btn-lg btn-block btn-primary", href: new_time_entry_path} Add Time Entry | ||||
|   %p | ||||
|     %a{class: "btn btn-lg btn-block btn-primary"} View Timesheet | ||||
|   %p | ||||
|  | ||||
							
								
								
									
										41
									
								
								app/views/time_entries/new.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/views/time_entries/new.haml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| %a{ class: "btn btn-default btn-lg", href: root_path} | ||||
|   %span{ class:"icon-home"} | ||||
| %h2 Add Time Entry | ||||
| 
 | ||||
| %p | ||||
|   .control-group | ||||
|     .controls | ||||
|       %input{id: "date_id", placeholder: "Date", type: "text", class: "datepicker input-small" } | ||||
|       .help-block | ||||
|   .control-group | ||||
|     .controls{ class: "bootstrap-timepicker"} | ||||
|       %label Start | ||||
|       %input{id: "start_time_id", placeholder: "Time ID", type: "text", class: "input-small" } | ||||
|       .help-block | ||||
|   .control-group | ||||
|     .controls | ||||
|       %label End | ||||
|       %input{id: "end_time_id", placeholder: "Time ID", type: "text", class: "input-small" } | ||||
|       .help-block | ||||
|   .control-group | ||||
|     .controls | ||||
|       .btn-group{ "data-toggle" => "buttons-radio"} | ||||
|         %label{ class: "btn btn-default"} | ||||
|           %input{ type: "radio", name: "action_id", value: 3} Volunteer | ||||
|         %label{ class: "btn btn-default"} | ||||
|           %input{ type: "radio", name: "action_id", value: 1} Personal | ||||
|         %label{ class: "btn btn-default"} | ||||
|           %input{ type: "radio", name: "action_id", value: 2} Staff | ||||
|     %input{ id: "bike_style_id", type: "hidden"} | ||||
|     .help-block | ||||
|   .control-group | ||||
|     .controls | ||||
|       %label | ||||
|         Worked on a bike? | ||||
|         %input{ type: "checkbox"} | ||||
|   .control-group | ||||
|     .controls | ||||
|       %textarea{id: "work_description", placeholder: "Work description", class: "input-lg" } | ||||
|   .control-group | ||||
|     .controls | ||||
|       %input{id: "add_bike_submit", value: "Add Time Entry", type: "button", class: "btn btn-lg btn-block btn-primary", "data-url" => "#{api_create_bike_path}"} | ||||
| @ -11,6 +11,8 @@ Velocipede::Application.routes.draw do | ||||
| 
 | ||||
|   get  'task_lists/:id/edit' => "task_lists#edit", as: "edit_task_list" | ||||
| 
 | ||||
|   get  'time_entries/new' => "time_entries#new", as: "new_time_entry" | ||||
| 
 | ||||
|   ########################### | ||||
|   # API Routes | ||||
|   scope 'api', :module => :api, defaults: {format: :json} do | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user