├── .gitignore ├── Gemfile ├── lib ├── bootstrap-timepicker-rails │ ├── version.rb │ ├── railtie.rb │ └── engine.rb └── bootstrap-timepicker-rails.rb ├── bootstrap-timepicker-rails.gemspec ├── Rakefile ├── README.md └── vendor └── assets ├── stylesheets └── bootstrap-timepicker.css └── javascripts ├── bootstrap-timepicker.js └── ] /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | *.gem 3 | bootstrap-timepicker-src 4 | *.swp 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | # Specify your gem's dependencies in bootstrap-rails.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/bootstrap-timepicker-rails/version.rb: -------------------------------------------------------------------------------- 1 | module BootstrapTimepickerRails 2 | module Rails 3 | VERSION = "0.1.3" 4 | end 5 | end -------------------------------------------------------------------------------- /lib/bootstrap-timepicker-rails/railtie.rb: -------------------------------------------------------------------------------- 1 | module BootstrapTimepickerRails 2 | module Rails 3 | class Railtie < ::Rails::Railtie; end 4 | end 5 | end -------------------------------------------------------------------------------- /lib/bootstrap-timepicker-rails/engine.rb: -------------------------------------------------------------------------------- 1 | module BootstrapTimepickerRails 2 | module Rails 3 | class Engine < ::Rails::Engine 4 | end 5 | end 6 | end -------------------------------------------------------------------------------- /lib/bootstrap-timepicker-rails.rb: -------------------------------------------------------------------------------- 1 | require "rails" 2 | require "bootstrap-timepicker-rails/version" 3 | 4 | module BootstrapTimepickerRails 5 | module Rails 6 | if ::Rails.version < "3.1" 7 | require "bootstrap-timepicker-rails/railtie" 8 | else 9 | require "bootstrap-timepicker-rails/engine" 10 | end 11 | end 12 | end -------------------------------------------------------------------------------- /bootstrap-timepicker-rails.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/bootstrap-timepicker-rails/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = ["Pratik Khadloya"] 6 | gem.email = ["tispratik@gmail.com"] 7 | gem.description = %q{Gemified https://github.com/jdewit/bootstrap-timepicker} 8 | gem.homepage = "https://github.com/jdewit/bootstrap-timepicker" 9 | gem.summary = gem.description 10 | 11 | gem.name = "bootstrap-timepicker-rails" 12 | gem.require_paths = ["lib"] 13 | gem.files = `git ls-files`.split("\n") 14 | gem.version = BootstrapTimepickerRails::Rails::VERSION 15 | 16 | gem.add_dependency "railties", ">= 3.0" 17 | gem.add_development_dependency "bundler", ">= 1.0" 18 | gem.add_development_dependency "rake" 19 | end 20 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | require File.expand_path('../lib/bootstrap-timepicker-rails/version', __FILE__) 3 | 4 | desc "Update assets" 5 | task 'update' do 6 | 7 | system("rm -rf bootstrap-timepicker-src") 8 | system("git clone git://github.com/jdewit/bootstrap-timepicker.git bootstrap-timepicker-src") 9 | 10 | system("cp bootstrap-timepicker-src/css/bootstrap-timepicker.min.css vendor/assets/stylesheets/bootstrap-timepicker.css") 11 | system("cp bootstrap-timepicker-src/js/bootstrap-timepicker.js vendor/assets/javascripts/bootstrap-timepicker.js") 12 | system("git status") 13 | end 14 | 15 | desc "Build the gem" 16 | task "build" do 17 | system("gem build bootstrap-timepicker-rails.gemspec") 18 | end 19 | 20 | desc "Publish the gem" 21 | task 'publish' do 22 | system("gem push bootstrap-timepicker-rails-#{BootstrapTimepickerRails::Rails::VERSION}.gem") 23 | system("git push") 24 | end 25 | 26 | desc "Build and publish the gem" 27 | task "release" do 28 | system("gem build bootstrap-timepicker-rails.gemspec") 29 | system("gem push bootstrap-timepicker-rails-#{BootstrapTimepickerRails::Rails::VERSION}.gem") 30 | system("git push") 31 | end 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap Timepicker for Rails 2 | This is the gemified version of https://github.com/jdewit/bootstrap-timepicker 3 | 4 | bootstrap-timepicker-rails project integrates Timepicker with Rails 3 assets pipeline. 5 | 6 | ## Rails > 3.1 7 | Include bootstrap-timepicker-rails in Gemfile; 8 | 9 | ``` ruby 10 | gem 'bootstrap-timepicker-rails' 11 | ``` 12 | 13 | or you can install from latest build; 14 | 15 | ``` ruby 16 | gem 'bootstrap-timepicker-rails', :require => 'bootstrap-timepicker-rails', 17 | :git => 'git://github.com/tispratik/bootstrap-timepicker-rails.git' 18 | ``` 19 | 20 | and run bundle install. 21 | 22 | ## Configuration 23 | 24 | Add this line to app/assets/stylesheets/application.css 25 | 26 | ``` css 27 | *= require bootstrap-timepicker 28 | ``` 29 | 30 | Add this line to app/assets/javascripts/application.js 31 | 32 | ``` javascript 33 | //= require bootstrap-timepicker 34 | ``` 35 | 36 | ## Using bootstrap-timepicker-rails 37 | 38 | Just call timepicker() with any selector. 39 | 40 | ```javascript 41 | $('.timepicker').timepicker() 42 | ``` 43 | 44 | Callback for time picked. 45 | 46 | ```javascript 47 | $('.timepicker').timepicker() 48 | .on('changeTime', function(ev) { 49 | alert('time has changed'); 50 | }); 51 | ``` 52 | Set time via data-time attribute. 53 | 54 | ```html 55 |
56 | 57 | 58 |
59 | 60 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/bootstrap-timepicker.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Timepicker Component for Twitter Bootstrap 3 | * 4 | * Copyright 2013 Joris de Wit 5 | * 6 | * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */.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:2px 3px 2px 2px}.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;left:9px;position:absolute;top:-7px}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent;content:"";display:inline-block;left:10px;position:absolute;top:-6px}.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}.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%}} -------------------------------------------------------------------------------- /vendor/assets/javascripts/bootstrap-timepicker.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Timepicker Component for Twitter Bootstrap 3 | * 4 | * Copyright 2013 Joris de Wit 5 | * 6 | * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | ;(function($, window, document, undefined) { 12 | 13 | 'use strict'; // jshint ;_; 14 | 15 | // TIMEPICKER PUBLIC CLASS DEFINITION 16 | var Timepicker = function(element, options) { 17 | this.widget = ''; 18 | this.$element = $(element); 19 | this.defaultTime = options.defaultTime; 20 | this.disableFocus = options.disableFocus; 21 | this.isOpen = options.isOpen; 22 | this.minuteStep = options.minuteStep; 23 | this.modalBackdrop = options.modalBackdrop; 24 | this.secondStep = options.secondStep; 25 | this.showInputs = options.showInputs; 26 | this.showMeridian = options.showMeridian; 27 | this.showSeconds = options.showSeconds; 28 | this.template = options.template; 29 | this.appendWidgetTo = options.appendWidgetTo; 30 | 31 | this._init(); 32 | }; 33 | 34 | Timepicker.prototype = { 35 | 36 | constructor: Timepicker, 37 | 38 | _init: function() { 39 | var self = this; 40 | 41 | if (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend')) { 42 | this.$element.parent('.input-append, .input-prepend').find('.add-on').on({ 43 | 'click.timepicker': $.proxy(this.showWidget, this) 44 | }); 45 | this.$element.on({ 46 | 'focus.timepicker': $.proxy(this.highlightUnit, this), 47 | 'click.timepicker': $.proxy(this.highlightUnit, this), 48 | 'keydown.timepicker': $.proxy(this.elementKeydown, this), 49 | 'blur.timepicker': $.proxy(this.blurElement, this) 50 | }); 51 | } else { 52 | if (this.template) { 53 | this.$element.on({ 54 | 'focus.timepicker': $.proxy(this.showWidget, this), 55 | 'click.timepicker': $.proxy(this.showWidget, this), 56 | 'blur.timepicker': $.proxy(this.blurElement, this) 57 | }); 58 | } else { 59 | this.$element.on({ 60 | 'focus.timepicker': $.proxy(this.highlightUnit, this), 61 | 'click.timepicker': $.proxy(this.highlightUnit, this), 62 | 'keydown.timepicker': $.proxy(this.elementKeydown, this), 63 | 'blur.timepicker': $.proxy(this.blurElement, this) 64 | }); 65 | } 66 | } 67 | 68 | if (this.template !== false) { 69 | this.$widget = $(this.getTemplate()).prependTo(this.$element.parents(this.appendWidgetTo)).on('click', $.proxy(this.widgetClick, this)); 70 | } else { 71 | this.$widget = false; 72 | } 73 | 74 | if (this.showInputs && this.$widget !== false) { 75 | this.$widget.find('input').each(function() { 76 | $(this).on({ 77 | 'click.timepicker': function() { $(this).select(); }, 78 | 'keydown.timepicker': $.proxy(self.widgetKeydown, self) 79 | }); 80 | }); 81 | } 82 | 83 | this.setDefaultTime(this.defaultTime); 84 | }, 85 | 86 | blurElement: function() { 87 | this.highlightedUnit = undefined; 88 | this.updateFromElementVal(); 89 | }, 90 | 91 | decrementHour: function() { 92 | if (this.showMeridian) { 93 | if (this.hour === 1) { 94 | this.hour = 12; 95 | } else if (this.hour === 12) { 96 | this.hour--; 97 | 98 | return this.toggleMeridian(); 99 | } else if (this.hour === 0) { 100 | this.hour = 11; 101 | 102 | return this.toggleMeridian(); 103 | } else { 104 | this.hour--; 105 | } 106 | } else { 107 | if (this.hour === 0) { 108 | this.hour = 23; 109 | } else { 110 | this.hour--; 111 | } 112 | } 113 | this.update(); 114 | }, 115 | 116 | decrementMinute: function(step) { 117 | var newVal; 118 | 119 | if (step) { 120 | newVal = this.minute - step; 121 | } else { 122 | newVal = this.minute - this.minuteStep; 123 | } 124 | 125 | if (newVal < 0) { 126 | this.decrementHour(); 127 | this.minute = newVal + 60; 128 | } else { 129 | this.minute = newVal; 130 | } 131 | this.update(); 132 | }, 133 | 134 | decrementSecond: function() { 135 | var newVal = this.second - this.secondStep; 136 | 137 | if (newVal < 0) { 138 | this.decrementMinute(true); 139 | this.second = newVal + 60; 140 | } else { 141 | this.second = newVal; 142 | } 143 | this.update(); 144 | }, 145 | 146 | elementKeydown: function(e) { 147 | switch (e.keyCode) { 148 | case 9: //tab 149 | this.updateFromElementVal(); 150 | 151 | switch (this.highlightedUnit) { 152 | case 'hour': 153 | e.preventDefault(); 154 | this.highlightNextUnit(); 155 | break; 156 | case 'minute': 157 | if (this.showMeridian || this.showSeconds) { 158 | e.preventDefault(); 159 | this.highlightNextUnit(); 160 | } 161 | break; 162 | case 'second': 163 | if (this.showMeridian) { 164 | e.preventDefault(); 165 | this.highlightNextUnit(); 166 | } 167 | break; 168 | } 169 | break; 170 | case 27: // escape 171 | this.updateFromElementVal(); 172 | break; 173 | case 37: // left arrow 174 | e.preventDefault(); 175 | this.highlightPrevUnit(); 176 | this.updateFromElementVal(); 177 | break; 178 | case 38: // up arrow 179 | e.preventDefault(); 180 | switch (this.highlightedUnit) { 181 | case 'hour': 182 | this.incrementHour(); 183 | this.highlightHour(); 184 | break; 185 | case 'minute': 186 | this.incrementMinute(); 187 | this.highlightMinute(); 188 | break; 189 | case 'second': 190 | this.incrementSecond(); 191 | this.highlightSecond(); 192 | break; 193 | case 'meridian': 194 | this.toggleMeridian(); 195 | this.highlightMeridian(); 196 | break; 197 | } 198 | break; 199 | case 39: // right arrow 200 | e.preventDefault(); 201 | this.updateFromElementVal(); 202 | this.highlightNextUnit(); 203 | break; 204 | case 40: // down arrow 205 | e.preventDefault(); 206 | switch (this.highlightedUnit) { 207 | case 'hour': 208 | this.decrementHour(); 209 | this.highlightHour(); 210 | break; 211 | case 'minute': 212 | this.decrementMinute(); 213 | this.highlightMinute(); 214 | break; 215 | case 'second': 216 | this.decrementSecond(); 217 | this.highlightSecond(); 218 | break; 219 | case 'meridian': 220 | this.toggleMeridian(); 221 | this.highlightMeridian(); 222 | break; 223 | } 224 | break; 225 | } 226 | }, 227 | 228 | formatTime: function(hour, minute, second, meridian) { 229 | hour = hour < 10 ? '0' + hour : hour; 230 | minute = minute < 10 ? '0' + minute : minute; 231 | second = second < 10 ? '0' + second : second; 232 | 233 | return hour + ':' + minute + (this.showSeconds ? ':' + second : '') + (this.showMeridian ? ' ' + meridian : ''); 234 | }, 235 | 236 | getCursorPosition: function() { 237 | var input = this.$element.get(0); 238 | 239 | if ('selectionStart' in input) {// Standard-compliant browsers 240 | 241 | return input.selectionStart; 242 | } else if (document.selection) {// IE fix 243 | input.focus(); 244 | var sel = document.selection.createRange(), 245 | selLen = document.selection.createRange().text.length; 246 | 247 | sel.moveStart('character', - input.value.length); 248 | 249 | return sel.text.length - selLen; 250 | } 251 | }, 252 | 253 | getTemplate: function() { 254 | var template, 255 | hourTemplate, 256 | minuteTemplate, 257 | secondTemplate, 258 | meridianTemplate, 259 | templateContent; 260 | 261 | if (this.showInputs) { 262 | hourTemplate = ''; 263 | minuteTemplate = ''; 264 | secondTemplate = ''; 265 | meridianTemplate = ''; 266 | } else { 267 | hourTemplate = ''; 268 | minuteTemplate = ''; 269 | secondTemplate = ''; 270 | meridianTemplate = ''; 271 | } 272 | 273 | templateContent = ''+ 274 | ''+ 275 | ''+ 276 | ''+ 277 | ''+ 278 | (this.showSeconds ? 279 | ''+ 280 | '' 281 | : '') + 282 | (this.showMeridian ? 283 | ''+ 284 | '' 285 | : '') + 286 | ''+ 287 | ''+ 288 | ' '+ 289 | ''+ 290 | ' '+ 291 | (this.showSeconds ? 292 | ''+ 293 | '' 294 | : '') + 295 | (this.showMeridian ? 296 | ''+ 297 | '' 298 | : '') + 299 | ''+ 300 | ''+ 301 | ''+ 302 | ''+ 303 | ''+ 304 | (this.showSeconds ? 305 | ''+ 306 | '' 307 | : '') + 308 | (this.showMeridian ? 309 | ''+ 310 | '' 311 | : '') + 312 | ''+ 313 | '
   
'+ hourTemplate +':'+ minuteTemplate +':'+ secondTemplate +' '+ meridianTemplate +'
  
'; 314 | 315 | switch(this.template) { 316 | case 'modal': 317 | template = ''; 329 | break; 330 | case 'dropdown': 331 | template = ''; 332 | break; 333 | } 334 | 335 | return template; 336 | }, 337 | 338 | getTime: function() { 339 | return this.formatTime(this.hour, this.minute, this.second, this.meridian); 340 | }, 341 | 342 | hideWidget: function() { 343 | if (this.isOpen === false) { 344 | return; 345 | } 346 | 347 | if (this.showInputs) { 348 | this.updateFromWidgetInputs(); 349 | } 350 | 351 | this.$element.trigger({ 352 | 'type': 'hide.timepicker', 353 | 'time': { 354 | 'value': this.getTime(), 355 | 'hours': this.hour, 356 | 'minutes': this.minute, 357 | 'seconds': this.second, 358 | 'meridian': this.meridian 359 | } 360 | }); 361 | 362 | if (this.template === 'modal') { 363 | this.$widget.modal('hide'); 364 | } else { 365 | this.$widget.removeClass('open'); 366 | } 367 | 368 | $(document).off('mousedown.timepicker'); 369 | 370 | this.isOpen = false; 371 | }, 372 | 373 | highlightUnit: function() { 374 | this.position = this.getCursorPosition(); 375 | if (this.position >= 0 && this.position <= 2) { 376 | this.highlightHour(); 377 | } else if (this.position >= 3 && this.position <= 5) { 378 | this.highlightMinute(); 379 | } else if (this.position >= 6 && this.position <= 8) { 380 | if (this.showSeconds) { 381 | this.highlightSecond(); 382 | } else { 383 | this.highlightMeridian(); 384 | } 385 | } else if (this.position >= 9 && this.position <= 11) { 386 | this.highlightMeridian(); 387 | } 388 | }, 389 | 390 | highlightNextUnit: function() { 391 | switch (this.highlightedUnit) { 392 | case 'hour': 393 | this.highlightMinute(); 394 | break; 395 | case 'minute': 396 | if (this.showSeconds) { 397 | this.highlightSecond(); 398 | } else if (this.showMeridian){ 399 | this.highlightMeridian(); 400 | } else { 401 | this.highlightHour(); 402 | } 403 | break; 404 | case 'second': 405 | if (this.showMeridian) { 406 | this.highlightMeridian(); 407 | } else { 408 | this.highlightHour(); 409 | } 410 | break; 411 | case 'meridian': 412 | this.highlightHour(); 413 | break; 414 | } 415 | }, 416 | 417 | highlightPrevUnit: function() { 418 | switch (this.highlightedUnit) { 419 | case 'hour': 420 | this.highlightMeridian(); 421 | break; 422 | case 'minute': 423 | this.highlightHour(); 424 | break; 425 | case 'second': 426 | this.highlightMinute(); 427 | break; 428 | case 'meridian': 429 | if (this.showSeconds) { 430 | this.highlightSecond(); 431 | } else { 432 | this.highlightMinute(); 433 | } 434 | break; 435 | } 436 | }, 437 | 438 | highlightHour: function() { 439 | var $element = this.$element.get(0); 440 | 441 | this.highlightedUnit = 'hour'; 442 | 443 | if ($element.setSelectionRange) { 444 | setTimeout(function() { 445 | $element.setSelectionRange(0,2); 446 | }, 0); 447 | } 448 | }, 449 | 450 | highlightMinute: function() { 451 | var $element = this.$element.get(0); 452 | 453 | this.highlightedUnit = 'minute'; 454 | 455 | if ($element.setSelectionRange) { 456 | setTimeout(function() { 457 | $element.setSelectionRange(3,5); 458 | }, 0); 459 | } 460 | }, 461 | 462 | highlightSecond: function() { 463 | var $element = this.$element.get(0); 464 | 465 | this.highlightedUnit = 'second'; 466 | 467 | if ($element.setSelectionRange) { 468 | setTimeout(function() { 469 | $element.setSelectionRange(6,8); 470 | }, 0); 471 | } 472 | }, 473 | 474 | highlightMeridian: function() { 475 | var $element = this.$element.get(0); 476 | 477 | this.highlightedUnit = 'meridian'; 478 | 479 | if ($element.setSelectionRange) { 480 | if (this.showSeconds) { 481 | setTimeout(function() { 482 | $element.setSelectionRange(9,11); 483 | }, 0); 484 | } else { 485 | setTimeout(function() { 486 | $element.setSelectionRange(6,8); 487 | }, 0); 488 | } 489 | } 490 | }, 491 | 492 | incrementHour: function() { 493 | if (this.showMeridian) { 494 | if (this.hour === 11) { 495 | this.hour++; 496 | return this.toggleMeridian(); 497 | } else if (this.hour === 12) { 498 | this.hour = 0; 499 | } 500 | } 501 | if (this.hour === 23) { 502 | return this.hour = 0; 503 | } 504 | this.hour++; 505 | this.update(); 506 | }, 507 | 508 | incrementMinute: function(step) { 509 | var newVal; 510 | 511 | if (step) { 512 | newVal = this.minute + step; 513 | } else { 514 | newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep); 515 | } 516 | 517 | if (newVal > 59) { 518 | this.incrementHour(); 519 | this.minute = newVal - 60; 520 | } else { 521 | this.minute = newVal; 522 | } 523 | this.update(); 524 | }, 525 | 526 | incrementSecond: function() { 527 | var newVal = this.second + this.secondStep - (this.second % this.secondStep); 528 | 529 | if (newVal > 59) { 530 | this.incrementMinute(true); 531 | this.second = newVal - 60; 532 | } else { 533 | this.second = newVal; 534 | } 535 | this.update(); 536 | }, 537 | 538 | remove: function() { 539 | $('document').off('.timepicker'); 540 | if (this.$widget) { 541 | this.$widget.remove(); 542 | } 543 | delete this.$element.data().timepicker; 544 | }, 545 | 546 | setDefaultTime: function(defaultTime){ 547 | if (!this.$element.val()) { 548 | if (defaultTime === 'current') { 549 | var dTime = new Date(), 550 | hours = dTime.getHours(), 551 | minutes = Math.floor(dTime.getMinutes() / this.minuteStep) * this.minuteStep, 552 | seconds = Math.floor(dTime.getSeconds() / this.secondStep) * this.secondStep, 553 | meridian = 'AM'; 554 | 555 | if (this.showMeridian) { 556 | if (hours === 0) { 557 | hours = 12; 558 | } else if (hours >= 12) { 559 | if (hours > 12) { 560 | hours = hours - 12; 561 | } 562 | meridian = 'PM'; 563 | } else { 564 | meridian = 'AM'; 565 | } 566 | } 567 | 568 | this.hour = hours; 569 | this.minute = minutes; 570 | this.second = seconds; 571 | this.meridian = meridian; 572 | 573 | this.update(); 574 | 575 | } else if (defaultTime === false) { 576 | this.hour = 0; 577 | this.minute = 0; 578 | this.second = 0; 579 | this.meridian = 'AM'; 580 | } else { 581 | this.setTime(defaultTime); 582 | } 583 | } else { 584 | this.updateFromElementVal(); 585 | } 586 | }, 587 | 588 | setTime: function(time) { 589 | var arr, 590 | timeArray; 591 | 592 | if (this.showMeridian) { 593 | arr = time.split(' '); 594 | timeArray = arr[0].split(':'); 595 | this.meridian = arr[1]; 596 | } else { 597 | timeArray = time.split(':'); 598 | } 599 | 600 | this.hour = parseInt(timeArray[0], 10); 601 | this.minute = parseInt(timeArray[1], 10); 602 | this.second = parseInt(timeArray[2], 10); 603 | 604 | if (isNaN(this.hour)) { 605 | this.hour = 0; 606 | } 607 | if (isNaN(this.minute)) { 608 | this.minute = 0; 609 | } 610 | 611 | if (this.showMeridian) { 612 | if (this.hour > 12) { 613 | this.hour = 12; 614 | } else if (this.hour < 1) { 615 | this.hour = 12; 616 | } 617 | 618 | if (this.meridian === 'am' || this.meridian === 'a') { 619 | this.meridian = 'AM'; 620 | } else if (this.meridian === 'pm' || this.meridian === 'p') { 621 | this.meridian = 'PM'; 622 | } 623 | 624 | if (this.meridian !== 'AM' && this.meridian !== 'PM') { 625 | this.meridian = 'AM'; 626 | } 627 | } else { 628 | if (this.hour >= 24) { 629 | this.hour = 23; 630 | } else if (this.hour < 0) { 631 | this.hour = 0; 632 | } 633 | } 634 | 635 | if (this.minute < 0) { 636 | this.minute = 0; 637 | } else if (this.minute >= 60) { 638 | this.minute = 59; 639 | } 640 | 641 | if (this.showSeconds) { 642 | if (isNaN(this.second)) { 643 | this.second = 0; 644 | } else if (this.second < 0) { 645 | this.second = 0; 646 | } else if (this.second >= 60) { 647 | this.second = 59; 648 | } 649 | } 650 | 651 | this.update(); 652 | }, 653 | 654 | showWidget: function() { 655 | if (this.isOpen) { 656 | return; 657 | } 658 | 659 | var self = this; 660 | $(document).on('mousedown.timepicker', function (e) { 661 | // Clicked outside the timepicker, hide it 662 | if ($(e.target).closest('.bootstrap-timepicker-widget').length === 0) { 663 | self.hideWidget(); 664 | } 665 | }); 666 | 667 | this.$element.trigger({ 668 | 'type': 'show.timepicker', 669 | 'time': { 670 | 'value': this.getTime(), 671 | 'hours': this.hour, 672 | 'minutes': this.minute, 673 | 'seconds': this.second, 674 | 'meridian': this.meridian 675 | } 676 | }); 677 | 678 | if (this.disableFocus) { 679 | this.$element.blur(); 680 | } 681 | 682 | this.updateFromElementVal(); 683 | 684 | if (this.template === 'modal') { 685 | this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this)); 686 | } else { 687 | if (this.isOpen === false) { 688 | this.$widget.addClass('open'); 689 | } 690 | } 691 | 692 | this.isOpen = true; 693 | }, 694 | 695 | toggleMeridian: function() { 696 | this.meridian = this.meridian === 'AM' ? 'PM' : 'AM'; 697 | this.update(); 698 | }, 699 | 700 | update: function() { 701 | this.$element.trigger({ 702 | 'type': 'changeTime.timepicker', 703 | 'time': { 704 | 'value': this.getTime(), 705 | 'hours': this.hour, 706 | 'minutes': this.minute, 707 | 'seconds': this.second, 708 | 'meridian': this.meridian 709 | } 710 | }); 711 | 712 | this.updateElement(); 713 | this.updateWidget(); 714 | }, 715 | 716 | updateElement: function() { 717 | this.$element.val(this.getTime()).change(); 718 | }, 719 | 720 | updateFromElementVal: function() { 721 | var val = this.$element.val(); 722 | 723 | if (val) { 724 | this.setTime(val); 725 | } 726 | }, 727 | 728 | updateWidget: function() { 729 | if (this.$widget === false) { 730 | return; 731 | } 732 | 733 | var hour = this.hour < 10 ? '0' + this.hour : this.hour, 734 | minute = this.minute < 10 ? '0' + this.minute : this.minute, 735 | second = this.second < 10 ? '0' + this.second : this.second; 736 | 737 | if (this.showInputs) { 738 | this.$widget.find('input.bootstrap-timepicker-hour').val(hour); 739 | this.$widget.find('input.bootstrap-timepicker-minute').val(minute); 740 | 741 | if (this.showSeconds) { 742 | this.$widget.find('input.bootstrap-timepicker-second').val(second); 743 | } 744 | if (this.showMeridian) { 745 | this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian); 746 | } 747 | } else { 748 | this.$widget.find('span.bootstrap-timepicker-hour').text(hour); 749 | this.$widget.find('span.bootstrap-timepicker-minute').text(minute); 750 | 751 | if (this.showSeconds) { 752 | this.$widget.find('span.bootstrap-timepicker-second').text(second); 753 | } 754 | if (this.showMeridian) { 755 | this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian); 756 | } 757 | } 758 | }, 759 | 760 | updateFromWidgetInputs: function() { 761 | if (this.$widget === false) { 762 | return; 763 | } 764 | var time = $('input.bootstrap-timepicker-hour', this.$widget).val() + ':' + 765 | $('input.bootstrap-timepicker-minute', this.$widget).val() + 766 | (this.showSeconds ? ':' + $('input.bootstrap-timepicker-second', this.$widget).val() : '') + 767 | (this.showMeridian ? ' ' + $('input.bootstrap-timepicker-meridian', this.$widget).val() : ''); 768 | 769 | this.setTime(time); 770 | }, 771 | 772 | widgetClick: function(e) { 773 | e.stopPropagation(); 774 | e.preventDefault(); 775 | 776 | var action = $(e.target).closest('a').data('action'); 777 | if (action) { 778 | this[action](); 779 | } 780 | }, 781 | 782 | widgetKeydown: function(e) { 783 | var $input = $(e.target).closest('input'), 784 | name = $input.attr('name'); 785 | 786 | switch (e.keyCode) { 787 | case 9: //tab 788 | if (this.showMeridian) { 789 | if (name === 'meridian') { 790 | return this.hideWidget(); 791 | } 792 | } else { 793 | if (this.showSeconds) { 794 | if (name === 'second') { 795 | return this.hideWidget(); 796 | } 797 | } else { 798 | if (name === 'minute') { 799 | return this.hideWidget(); 800 | } 801 | } 802 | } 803 | 804 | this.updateFromWidgetInputs(); 805 | break; 806 | case 27: // escape 807 | this.hideWidget(); 808 | break; 809 | case 38: // up arrow 810 | e.preventDefault(); 811 | switch (name) { 812 | case 'hour': 813 | this.incrementHour(); 814 | break; 815 | case 'minute': 816 | this.incrementMinute(); 817 | break; 818 | case 'second': 819 | this.incrementSecond(); 820 | break; 821 | case 'meridian': 822 | this.toggleMeridian(); 823 | break; 824 | } 825 | break; 826 | case 40: // down arrow 827 | e.preventDefault(); 828 | switch (name) { 829 | case 'hour': 830 | this.decrementHour(); 831 | break; 832 | case 'minute': 833 | this.decrementMinute(); 834 | break; 835 | case 'second': 836 | this.decrementSecond(); 837 | break; 838 | case 'meridian': 839 | this.toggleMeridian(); 840 | break; 841 | } 842 | break; 843 | } 844 | } 845 | }; 846 | 847 | 848 | //TIMEPICKER PLUGIN DEFINITION 849 | $.fn.timepicker = function(option) { 850 | var args = Array.apply(null, arguments); 851 | args.shift(); 852 | return this.each(function() { 853 | var $this = $(this), 854 | data = $this.data('timepicker'), 855 | options = typeof option === 'object' && option; 856 | 857 | if (!data) { 858 | $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data())))); 859 | } 860 | 861 | if (typeof option === 'string') { 862 | data[option].apply(data, args); 863 | } 864 | }); 865 | }; 866 | 867 | $.fn.timepicker.defaults = { 868 | defaultTime: 'current', 869 | disableFocus: false, 870 | isOpen: false, 871 | minuteStep: 15, 872 | modalBackdrop: false, 873 | secondStep: 15, 874 | showSeconds: false, 875 | showInputs: true, 876 | showMeridian: true, 877 | template: 'dropdown', 878 | appendWidgetTo: '.bootstrap-timepicker' 879 | }; 880 | 881 | $.fn.timepicker.Constructor = Timepicker; 882 | 883 | })(jQuery, window, document); 884 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/]: -------------------------------------------------------------------------------- 1 | /* ========================================================= 2 | * bootstrap-timepicker.js 3 | * http://www.github.com/jdewit/bootstrap-timepicker 4 | * ========================================================= 5 | * Copyright 2012 6 | * 7 | * Created By: 8 | * Joris de Wit @joris_dewit 9 | * 10 | * Contributions By: 11 | * Gilbert @mindeavor 12 | * Koen Punt info@koenpunt.nl 13 | * Nek 14 | * Chris Martin 15 | * Dominic Barnes contact@dominicbarnes.us 16 | * 17 | * Licensed under the Apache License, Version 2.0 (the "License"); 18 | * you may not use this file except in compliance with the License. 19 | * You may obtain a copy of the License at 20 | * 21 | * http://www.apache.org/licenses/LICENSE-2.0 22 | * 23 | * Unless required by applicable law or agreed to in writing, software 24 | * distributed under the License is distributed on an "AS IS" BASIS, 25 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | * See the License for the specific language governing permissions and 27 | * limitations under the License. 28 | * ========================================================= */ 29 | 30 | !function($) { 31 | 32 | "use strict"; // jshint ;_; 33 | 34 | /* TIMEPICKER PUBLIC CLASS DEFINITION 35 | * ================================== */ 36 | var Timepicker = function(element, options) { 37 | this.$element = $(element); 38 | this.options = $.extend({}, $.fn.timepicker.defaults, options, this.$element.data()); 39 | this.minuteStep = this.options.minuteStep || this.minuteStep; 40 | this.secondStep = this.options.secondStep || this.secondStep; 41 | this.showMeridian = this.options.showMeridian || this.showMeridian; 42 | this.showSeconds = this.options.showSeconds || this.showSeconds; 43 | this.showInputs = this.options.showInputs || this.showInputs; 44 | this.disableFocus = this.options.disableFocus || this.disableFocus; 45 | this.template = this.options.template || this.template; 46 | this.modalBackdrop = this.options.modalBackdrop || this.modalBackdrop; 47 | this.defaultTime = this.$element.time || this.options.defaultTime || this.defaultTime; 48 | console.log(this.$element.time) 49 | console.log(this.options) 50 | this.open = false; 51 | this.init(); 52 | }; 53 | 54 | Timepicker.prototype = { 55 | 56 | constructor: Timepicker 57 | 58 | , init: function () { 59 | if (this.$element.parent().hasClass('input-append')) { 60 | this.$element.parent('.input-append').find('.add-on').on('click', $.proxy(this.showWidget, this)); 61 | this.$element.on({ 62 | focus: $.proxy(this.highlightUnit, this), 63 | click: $.proxy(this.highlightUnit, this), 64 | keypress: $.proxy(this.elementKeypress, this), 65 | blur: $.proxy(this.blurElement, this) 66 | }); 67 | 68 | } else { 69 | if (this.template) { 70 | this.$element.on({ 71 | focus: $.proxy(this.showWidget, this), 72 | click: $.proxy(this.showWidget, this), 73 | blur: $.proxy(this.blurElement, this) 74 | }); 75 | } else { 76 | this.$element.on({ 77 | focus: $.proxy(this.highlightUnit, this), 78 | click: $.proxy(this.highlightUnit, this), 79 | keypress: $.proxy(this.elementKeypress, this), 80 | blur: $.proxy(this.blurElement, this) 81 | }); 82 | } 83 | } 84 | 85 | 86 | this.$widget = $(this.getTemplate()).appendTo('body'); 87 | 88 | this.$widget.on('click', $.proxy(this.widgetClick, this)); 89 | 90 | if (this.showInputs) { 91 | this.$widget.find('input').on({ 92 | click: function() { this.select(); }, 93 | keypress: $.proxy(this.widgetKeypress, this), 94 | change: $.proxy(this.updateFromWidgetInputs, this) 95 | }); 96 | } 97 | 98 | this.setDefaultTime(this.defaultTime); 99 | } 100 | 101 | , showWidget: function(e) { 102 | e.stopPropagation(); 103 | e.preventDefault(); 104 | 105 | if (this.open) { 106 | return; 107 | } 108 | 109 | this.$element.trigger('show'); 110 | 111 | if (this.disableFocus) { 112 | this.$element.blur(); 113 | } 114 | 115 | var pos = $.extend({}, this.$element.offset(), { 116 | height: this.$element[0].offsetHeight 117 | }); 118 | 119 | this.updateFromElementVal(); 120 | 121 | $('html') 122 | .trigger('click.timepicker.data-api') 123 | .one('click.timepicker.data-api', $.proxy(this.hideWidget, this)); 124 | 125 | if (this.template === 'modal') { 126 | this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this)); 127 | } else { 128 | this.$widget.css({ 129 | top: pos.top + pos.height 130 | , left: pos.left 131 | }) 132 | 133 | if (!this.open) { 134 | this.$widget.addClass('open'); 135 | } 136 | } 137 | 138 | this.open = true; 139 | this.$element.trigger('shown'); 140 | } 141 | 142 | , hideWidget: function(){ 143 | this.$element.trigger('hide'); 144 | 145 | if (this.template === 'modal') { 146 | this.$widget.modal('hide'); 147 | } else { 148 | this.$widget.removeClass('open'); 149 | } 150 | this.open = false; 151 | this.$element.trigger('hidden'); 152 | } 153 | 154 | , widgetClick: function(e) { 155 | e.stopPropagation(); 156 | e.preventDefault(); 157 | 158 | var action = $(e.target).closest('a').data('action'); 159 | if (action) { 160 | this[action](); 161 | this.update(); 162 | } 163 | } 164 | 165 | , widgetKeypress: function(e) { 166 | var input = $(e.target).closest('input').attr('name'); 167 | 168 | switch (e.keyCode) { 169 | case 9: //tab 170 | if (this.showMeridian) { 171 | if (input == 'meridian') { 172 | this.hideWidget(); 173 | } 174 | } else { 175 | if (this.showSeconds) { 176 | if (input == 'second') { 177 | this.hideWidget(); 178 | } 179 | } else { 180 | if (input == 'minute') { 181 | this.hideWidget(); 182 | } 183 | } 184 | } 185 | break; 186 | case 27: // escape 187 | this.hideWidget(); 188 | break; 189 | case 38: // up arrow 190 | switch (input) { 191 | case 'hour': 192 | this.incrementHour(); 193 | break; 194 | case 'minute': 195 | this.incrementMinute(); 196 | break; 197 | case 'second': 198 | this.incrementSecond(); 199 | break; 200 | case 'meridian': 201 | this.toggleMeridian(); 202 | break; 203 | } 204 | this.update(); 205 | break; 206 | case 40: // down arrow 207 | switch (input) { 208 | case 'hour': 209 | this.decrementHour(); 210 | break; 211 | case 'minute': 212 | this.decrementMinute(); 213 | break; 214 | case 'second': 215 | this.decrementSecond(); 216 | break; 217 | case 'meridian': 218 | this.toggleMeridian(); 219 | break; 220 | } 221 | this.update(); 222 | break; 223 | } 224 | } 225 | 226 | , elementKeypress: function(e) { 227 | var input = this.$element.get(0); 228 | switch (e.keyCode) { 229 | case 0: //input 230 | break; 231 | case 9: //tab 232 | this.updateFromElementVal(); 233 | if (this.showMeridian) { 234 | if (this.highlightedUnit != 'meridian') { 235 | e.preventDefault(); 236 | this.highlightNextUnit(); 237 | } 238 | } else { 239 | if (this.showSeconds) { 240 | if (this.highlightedUnit != 'second') { 241 | e.preventDefault(); 242 | this.highlightNextUnit(); 243 | } 244 | } else { 245 | if (this.highlightedUnit != 'minute') { 246 | e.preventDefault(); 247 | this.highlightNextUnit(); 248 | } 249 | } 250 | } 251 | break; 252 | case 27: // escape 253 | this.updateFromElementVal(); 254 | break; 255 | case 37: // left arrow 256 | this.updateFromElementVal(); 257 | this.highlightPrevUnit(); 258 | break; 259 | case 38: // up arrow 260 | switch (this.highlightedUnit) { 261 | case 'hour': 262 | this.incrementHour(); 263 | break; 264 | case 'minute': 265 | this.incrementMinute(); 266 | break; 267 | case 'second': 268 | this.incrementSecond(); 269 | break; 270 | case 'meridian': 271 | this.toggleMeridian(); 272 | break; 273 | } 274 | this.updateElement(); 275 | break; 276 | case 39: // right arrow 277 | this.updateFromElementVal(); 278 | this.highlightNextUnit(); 279 | break; 280 | case 40: // down arrow 281 | switch (this.highlightedUnit) { 282 | case 'hour': 283 | this.decrementHour(); 284 | break; 285 | case 'minute': 286 | this.decrementMinute(); 287 | break; 288 | case 'second': 289 | this.decrementSecond(); 290 | break; 291 | case 'meridian': 292 | this.toggleMeridian(); 293 | break; 294 | } 295 | this.updateElement(); 296 | break; 297 | } 298 | 299 | if (e.keyCode !== 0 && e.keyCode !== 8 && e.keyCode !== 9 && e.keyCode !== 46) { 300 | e.preventDefault(); 301 | } 302 | } 303 | 304 | , setValues: function(time) { 305 | if (this.showMeridian) { 306 | var arr = time.split(' '); 307 | var timeArray = arr[0].split(':'); 308 | this.meridian = arr[1]; 309 | } else { 310 | var timeArray = time.split(':'); 311 | } 312 | 313 | this.hour = parseInt(timeArray[0], 10); 314 | this.minute = parseInt(timeArray[1], 10); 315 | this.second = parseInt(timeArray[2], 10); 316 | 317 | if (isNaN(this.hour)) { 318 | this.hour = 0; 319 | } 320 | if (isNaN(this.minute)) { 321 | this.minute = 0; 322 | } 323 | 324 | if (this.showMeridian) { 325 | if (this.hour > 12) { 326 | this.hour = 12; 327 | } else if (this.hour < 1) { 328 | this.hour = 1; 329 | } 330 | 331 | if (this.meridian == 'am' || this.meridian == 'a') { 332 | this.meridian = 'AM'; 333 | } else if (this.meridian == 'pm' || this.meridian == 'p') { 334 | this.meridian = 'PM'; 335 | } 336 | 337 | if (this.meridian != 'AM' && this.meridian != 'PM') { 338 | this.meridian = 'AM'; 339 | } 340 | } else { 341 | if (this.hour >= 24) { 342 | this.hour = 23; 343 | } else if (this.hour < 0) { 344 | this.hour = 0; 345 | } 346 | } 347 | 348 | if (this.minute < 0) { 349 | this.minute = 0; 350 | } else if (this.minute >= 60) { 351 | this.minute = 59; 352 | } 353 | 354 | if (this.showSeconds) { 355 | if (isNaN(this.second)) { 356 | this.second = 0; 357 | } else if (this.second < 0) { 358 | this.second = 0; 359 | } else if (this.second >= 60) { 360 | this.second = 59; 361 | } 362 | } 363 | 364 | this.updateElement(); 365 | this.updateWidget(); 366 | } 367 | 368 | , setMeridian: function(meridian) { 369 | if (meridian == 'a' || meridian == 'am' || meridian == 'AM' ) { 370 | this.meridian = 'AM'; 371 | } else if (meridian == 'p' || meridian == 'pm' || meridian == 'PM' ) { 372 | this.meridian = 'PM'; 373 | } else { 374 | this.updateWidget(); 375 | } 376 | 377 | this.updateElement(); 378 | } 379 | 380 | , setDefaultTime: function(defaultTime){ 381 | if (defaultTime) { 382 | if (defaultTime === 'current') { 383 | var dTime = new Date(); 384 | var hours = dTime.getHours(); 385 | var minutes = Math.floor(dTime.getMinutes() / this.minuteStep) * this.minuteStep; 386 | var seconds = Math.floor(dTime.getSeconds() / this.secondStep) * this.secondStep; 387 | var meridian = "AM"; 388 | if (this.showMeridian) { 389 | if (hours === 0) { 390 | hours = 12; 391 | } else if (hours >= 12) { 392 | if (hours > 12) { 393 | hours = hours - 12; 394 | } 395 | meridian = "PM"; 396 | } else { 397 | meridian = "AM"; 398 | } 399 | } 400 | this.hour = hours; 401 | this.minute = minutes; 402 | this.second = seconds; 403 | this.meridian = meridian; 404 | } else if (defaultTime === 'value') { 405 | this.setValues(this.$element.val()); 406 | } else { 407 | this.setValues(defaultTime); 408 | } 409 | this.update(); 410 | } else { 411 | this.hour = 0; 412 | this.minute = 0; 413 | this.second = 0; 414 | } 415 | } 416 | 417 | , formatTime: function(hour, minute, second, meridian) { 418 | hour = hour < 10 ? '0' + hour : hour; 419 | minute = minute < 10 ? '0' + minute : minute; 420 | second = second < 10 ? '0' + second : second; 421 | 422 | return hour + ':' + minute + (this.showSeconds ? ':' + second : '') + (this.showMeridian ? ' ' + meridian : ''); 423 | } 424 | 425 | , getTime: function() { 426 | return this.formatTime(this.hour, this.minute, this.second, this.meridian); 427 | } 428 | 429 | , setTime: function(time) { 430 | this.setValues(time); 431 | this.update(); 432 | } 433 | 434 | , update: function() { 435 | this.updateElement(); 436 | this.updateWidget(); 437 | this.$element.trigger({ 438 | type: 'changeTime', 439 | time: this.time 440 | }); 441 | } 442 | 443 | , blurElement: function() { 444 | this.highlightedUnit = undefined; 445 | this.updateFromElementVal(); 446 | } 447 | 448 | , updateElement: function() { 449 | var time = this.getTime(); 450 | 451 | this.$element.val(time).change(); 452 | 453 | switch (this.highlightedUnit) { 454 | case 'hour': 455 | this.highlightHour(); 456 | break; 457 | case 'minute': 458 | this.highlightMinute(); 459 | break; 460 | case 'second': 461 | this.highlightSecond(); 462 | break; 463 | case 'meridian': 464 | this.highlightMeridian(); 465 | break; 466 | } 467 | } 468 | 469 | , updateWidget: function() { 470 | if (this.showInputs) { 471 | this.$widget.find('input.bootstrap-timepicker-hour').val(this.hour < 10 ? '0' + this.hour : this.hour); 472 | this.$widget.find('input.bootstrap-timepicker-minute').val(this.minute < 10 ? '0' + this.minute : this.minute); 473 | if (this.showSeconds) { 474 | this.$widget.find('input.bootstrap-timepicker-second').val(this.second < 10 ? '0' + this.second : this.second); 475 | } 476 | if (this.showMeridian) { 477 | this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian); 478 | } 479 | } else { 480 | this.$widget.find('span.bootstrap-timepicker-hour').text(this.hour); 481 | this.$widget.find('span.bootstrap-timepicker-minute').text(this.minute < 10 ? '0' + this.minute : this.minute); 482 | if (this.showSeconds) { 483 | this.$widget.find('span.bootstrap-timepicker-second').text(this.second < 10 ? '0' + this.second : this.second); 484 | } 485 | if (this.showMeridian) { 486 | this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian); 487 | } 488 | } 489 | } 490 | 491 | , updateFromElementVal: function (e) { 492 | var time = this.$element.val(); 493 | if (time) { 494 | this.setValues(time); 495 | this.updateWidget(); 496 | } 497 | } 498 | 499 | , updateFromWidgetInputs: function () { 500 | var time = $('input.bootstrap-timepicker-hour', this.$widget).val() + ':' + 501 | $('input.bootstrap-timepicker-minute', this.$widget).val() + 502 | (this.showSeconds ? 503 | ':' + $('input.bootstrap-timepicker-second', this.$widget).val() 504 | : '') + 505 | (this.showMeridian ? 506 | ' ' + $('input.bootstrap-timepicker-meridian', this.$widget).val() 507 | : ''); 508 | 509 | this.setValues(time); 510 | } 511 | 512 | , getCursorPosition: function() { 513 | var input = this.$element.get(0); 514 | 515 | if ('selectionStart' in input) { 516 | // Standard-compliant browsers 517 | return input.selectionStart; 518 | } else if (document.selection) { 519 | // IE fix 520 | input.focus(); 521 | var sel = document.selection.createRange(); 522 | var selLen = document.selection.createRange().text.length; 523 | sel.moveStart('character', - input.value.length); 524 | 525 | return sel.text.length - selLen; 526 | } 527 | } 528 | 529 | , highlightUnit: function () { 530 | var input = this.$element.get(0); 531 | 532 | this.position = this.getCursorPosition(); 533 | if (this.position >= 0 && this.position <= 2) { 534 | this.highlightHour(); 535 | } else if (this.position >= 3 && this.position <= 5) { 536 | this.highlightMinute(); 537 | } else if (this.position >= 6 && this.position <= 8) { 538 | if (this.showSeconds) { 539 | this.highlightSecond(); 540 | } else { 541 | this.highlightMeridian(); 542 | } 543 | } else if (this.position >= 9 && this.position <= 11) { 544 | this.highlightMeridian(); 545 | } 546 | } 547 | 548 | , highlightNextUnit: function() { 549 | switch (this.highlightedUnit) { 550 | case 'hour': 551 | this.highlightMinute(); 552 | break; 553 | case 'minute': 554 | if (this.showSeconds) { 555 | this.highlightSecond(); 556 | } else { 557 | this.highlightMeridian(); 558 | } 559 | break; 560 | case 'second': 561 | this.highlightMeridian(); 562 | break; 563 | case 'meridian': 564 | this.highlightHour(); 565 | break; 566 | } 567 | } 568 | 569 | , highlightPrevUnit: function() { 570 | switch (this.highlightedUnit) { 571 | case 'hour': 572 | this.highlightMeridian(); 573 | break; 574 | case 'minute': 575 | this.highlightHour(); 576 | break; 577 | case 'second': 578 | this.highlightMinute(); 579 | break; 580 | case 'meridian': 581 | if (this.showSeconds) { 582 | this.highlightSecond(); 583 | } else { 584 | this.highlightMinute(); 585 | } 586 | break; 587 | } 588 | } 589 | 590 | , highlightHour: function() { 591 | this.highlightedUnit = 'hour'; 592 | this.$element.get(0).setSelectionRange(0,2); 593 | } 594 | 595 | , highlightMinute: function() { 596 | this.highlightedUnit = 'minute'; 597 | this.$element.get(0).setSelectionRange(3,5); 598 | } 599 | 600 | , highlightSecond: function() { 601 | this.highlightedUnit = 'second'; 602 | this.$element.get(0).setSelectionRange(6,8); 603 | } 604 | 605 | , highlightMeridian: function() { 606 | this.highlightedUnit = 'meridian'; 607 | if (this.showSeconds) { 608 | this.$element.get(0).setSelectionRange(9,11); 609 | } else { 610 | this.$element.get(0).setSelectionRange(6,8); 611 | } 612 | } 613 | 614 | , incrementHour: function() { 615 | if (this.showMeridian) { 616 | if (this.hour === 11) { 617 | this.toggleMeridian(); 618 | } else if (this.hour === 12) { 619 | return this.hour = 1; 620 | } 621 | } 622 | if (this.hour === 23) { 623 | return this.hour = 0; 624 | } 625 | this.hour = this.hour + 1; 626 | } 627 | 628 | , decrementHour: function() { 629 | if (this.showMeridian) { 630 | if (this.hour === 1) { 631 | return this.hour = 12; 632 | } 633 | else if (this.hour === 12) { 634 | this.toggleMeridian(); 635 | } 636 | } 637 | if (this.hour === 0) { 638 | return this.hour = 23; 639 | } 640 | this.hour = this.hour - 1; 641 | } 642 | 643 | , incrementMinute: function() { 644 | var newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep); 645 | if (newVal > 59) { 646 | this.incrementHour(); 647 | this.minute = newVal - 60; 648 | } else { 649 | this.minute = newVal; 650 | } 651 | } 652 | 653 | , decrementMinute: function() { 654 | var newVal = this.minute - this.minuteStep; 655 | if (newVal < 0) { 656 | this.decrementHour(); 657 | this.minute = newVal + 60; 658 | } else { 659 | this.minute = newVal; 660 | } 661 | } 662 | 663 | , incrementSecond: function() { 664 | var newVal = this.second + this.secondStep - (this.second % this.secondStep); 665 | if (newVal > 59) { 666 | this.incrementMinute(); 667 | this.second = newVal - 60; 668 | } else { 669 | this.second = newVal; 670 | } 671 | } 672 | 673 | , decrementSecond: function() { 674 | var newVal = this.second - this.secondStep; 675 | if (newVal < 0) { 676 | this.decrementMinute(); 677 | this.second = newVal + 60; 678 | } else { 679 | this.second = newVal; 680 | } 681 | } 682 | 683 | , toggleMeridian: function() { 684 | this.meridian = this.meridian === 'AM' ? 'PM' : 'AM'; 685 | 686 | this.update(); 687 | } 688 | 689 | , getTemplate: function() { 690 | if (this.options.templates[this.options.template]) { 691 | return this.options.templates[this.options.template]; 692 | } 693 | if (this.showInputs) { 694 | var hourTemplate = ''; 695 | var minuteTemplate = ''; 696 | var secondTemplate = ''; 697 | var meridianTemplate = ''; 698 | } else { 699 | var hourTemplate = ''; 700 | var minuteTemplate = ''; 701 | var secondTemplate = ''; 702 | var meridianTemplate = ''; 703 | } 704 | var templateContent = ''+ 705 | ''+ 706 | ''+ 707 | ''+ 708 | ''+ 709 | (this.showSeconds ? 710 | ''+ 711 | '' 712 | : '') + 713 | (this.showMeridian ? 714 | ''+ 715 | '' 716 | : '') + 717 | ''+ 718 | ''+ 719 | ' '+ 720 | ''+ 721 | ' '+ 722 | (this.showSeconds ? 723 | ''+ 724 | '' 725 | : '') + 726 | (this.showMeridian ? 727 | ''+ 728 | '' 729 | : '') + 730 | ''+ 731 | ''+ 732 | ''+ 733 | ''+ 734 | ''+ 735 | (this.showSeconds ? 736 | ''+ 737 | '' 738 | : '') + 739 | (this.showMeridian ? 740 | ''+ 741 | '' 742 | : '') + 743 | ''+ 744 | '
   
'+ hourTemplate +':'+ minuteTemplate +':'+ secondTemplate +' '+ meridianTemplate +'
  
'; 745 | 746 | var template; 747 | switch(this.options.template) { 748 | case 'modal': 749 | template = ''; 761 | 762 | break; 763 | case 'dropdown': 764 | template = ''; 767 | break; 768 | 769 | } 770 | return template; 771 | } 772 | }; 773 | 774 | 775 | /* TIMEPICKER PLUGIN DEFINITION 776 | * =========================== */ 777 | 778 | $.fn.timepicker = function (option) { 779 | return this.each(function () { 780 | var $this = $(this) 781 | , data = $this.data('timepicker') 782 | , options = typeof option == 'object' && option; 783 | if (!data) { 784 | $this.data('timepicker', (data = new Timepicker(this, options))); 785 | } 786 | if (typeof option == 'string') { 787 | data[option](); 788 | } 789 | }) 790 | } 791 | 792 | $.fn.timepicker.defaults = { 793 | minuteStep: 15 794 | , secondStep: 15 795 | , disableFocus: false 796 | , defaultTime: 'current' 797 | , showSeconds: false 798 | , showInputs: true 799 | , showMeridian: true 800 | , template: 'dropdown' 801 | , modalBackdrop: false 802 | , templates: {} // set custom templates 803 | } 804 | 805 | $.fn.timepicker.Constructor = Timepicker 806 | }(window.jQuery); 807 | --------------------------------------------------------------------------------