bootstrap-timepicker-rails-addon 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c43149fd64f5a73bfac3fabf476ba171f611fec
4
- data.tar.gz: 6574c731da5c59d6d19b6f3a4bff706e4b78d2d4
3
+ metadata.gz: d53e7c7b6dc408b23358a61a8a105affdd3a1894
4
+ data.tar.gz: fafa6ddbf978c829658e6ff259686b3afd9eb50b
5
5
  SHA512:
6
- metadata.gz: b336fca9f09bb8f2bc2af8681341a118da95b4cbcf4106ed214652df218964a674ee843999a69170a1b89c192b6f192d86aeb1afcc8b2db775fd0085cb58c2ab
7
- data.tar.gz: 678ffdfc30c0fd73e8d93936a7b192cd705941e7175ba679e56d78c71bded94be9f9e9614965d8198b19a224de4672e176292b1461578302e4347dbd8f235a5e
6
+ metadata.gz: 0591e472cfe6a3dc622a12e67fb6ea46ce74a22afb0118fd008743ada85f54cfe5c935d2bbaa664526d2960a4b85791208d4f9735b69465763c220441f14d26b
7
+ data.tar.gz: d721ffc180649f5c0953fe8542d87b92172dd43d992c5945bfc6833294d67db60df60928720d6785e04deffae2d785e168c33db0cf60e057d3f140157ff9983b
data/README.md CHANGED
@@ -1,19 +1,28 @@
1
1
  # Bootstrap::Timepicker::Rails::Addon
2
2
  This is the GEMified version of [bootstrap-timepicker](https://github.com/jdewit/bootstrap-timepicker)
3
3
 
4
- bootstrap-timepicker-rails-addon project integrates Timepicker for Twitter Bootstrap with Rails 3 and 4 assets pipeline.
4
+ bootstrap-timepicker-rails-addon project integrates Timepicker for Twitter Bootstrap 3 with Rails 3 and 4 assets pipeline.
5
5
 
6
6
  ## Installation
7
7
 
8
8
  Add this line to your application's Gemfile:
9
9
 
10
+ 1) if you used Bootstrap 3 version,
11
+ ```ruby
12
+ gem 'bootstrap-sass', '~> 3.3.5'
13
+ gem 'bootstrap-timepicker-rails-addon', '~> 0.5.1'
14
+ ```
15
+
16
+ 2) if you used Bootstrap 2 version,
17
+ ```ruby
10
18
  gem 'bootstrap-sass', '~> 2.3.2.0'
11
- gem 'bootstrap-timepicker-rails-addon'
19
+ gem 'bootstrap-timepicker-rails-addon', '0.3.0'
20
+ ```
12
21
 
13
- Or you can install from latest build:
22
+ Or you can install from latest build(only support Bootstrap 3 version in master branch):
14
23
 
15
24
  ```ruby
16
- gem 'bootstrap-sass', '~> 2.3.2.0'
25
+ gem 'bootstrap-sass', '~> 3.3.5'
17
26
  gem 'bootstrap-timepicker-rails-addon', :require => 'bootstrap-timepicker-rails-addon',
18
27
  :git => 'git://github.com/ywjno/bootstrap-timepicker-rails-addon.git'
19
28
  ```
@@ -32,9 +41,9 @@ Add this line to app/assets/javascripts/application.js
32
41
 
33
42
  //= require bootstrap-timepicker
34
43
 
35
- Add this line to app/assets/stylesheets/application.css
44
+ Add this line to app/assets/stylesheets/application.css.scss
36
45
 
37
- *= require bootstrap-timepicker
46
+ @import "bootstrap-timepicker";
38
47
 
39
48
  Just call timepicker() with any selector in view.
40
49
 
@@ -45,9 +54,9 @@ $('#timepicker').timepicker();
45
54
  And here is the html code sample.
46
55
 
47
56
  ```html
48
- <div class="input-append bootstrap-timepicker">
49
- <input id="timepicker" type="text" class="input-small">
50
- <span class="add-on"><i class="icon-time"></i></span>
57
+ <div class="input-group bootstrap-timepicker timepicker">
58
+ <input id="timepicker1" type="text" class="form-control input-small">
59
+ <span class="input-group-addon"><i class="glyphicon glyphicon-time"></i></span>
51
60
  </div>
52
61
  ```
53
62
 
@@ -2,7 +2,7 @@ module Bootstrap
2
2
  module Timepicker
3
3
  module Rails
4
4
  module Addon
5
- VERSION = "0.3.0"
5
+ VERSION = "0.5.1"
6
6
  end
7
7
  end
8
8
  end
@@ -8,7 +8,7 @@
8
8
  * For the full copyright and license information, please view the LICENSE
9
9
  * file that was distributed with this source code.
10
10
  */
11
- (function($, window, document, undefined) {
11
+ (function($, window, document) {
12
12
  'use strict';
13
13
 
14
14
  // TIMEPICKER PUBLIC CLASS DEFINITION
@@ -23,14 +23,26 @@
23
23
  this.modalBackdrop = options.modalBackdrop;
24
24
  this.orientation = options.orientation;
25
25
  this.secondStep = options.secondStep;
26
+ this.snapToStep = options.snapToStep;
26
27
  this.showInputs = options.showInputs;
27
28
  this.showMeridian = options.showMeridian;
28
29
  this.showSeconds = options.showSeconds;
29
30
  this.template = options.template;
30
31
  this.appendWidgetTo = options.appendWidgetTo;
31
32
  this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;
32
- this.maxHours = options.maxHours-1;
33
-
33
+ this.maxHours = options.maxHours;
34
+ this.explicitMode = options.explicitMode; // If true 123 = 1:23, 12345 = 1:23:45, else invalid.
35
+
36
+ this.handleDocumentClick = function (e) {
37
+ var self = e.data.scope;
38
+ // This condition was inspired by bootstrap-datepicker.
39
+ // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
40
+ if (!(self.$element.parent().find(e.target).length ||
41
+ self.$widget.is(e.target) ||
42
+ self.$widget.find(e.target).length)) {
43
+ self.hideWidget();
44
+ }
45
+ };
34
46
  this._init();
35
47
  };
36
48
 
@@ -40,8 +52,8 @@
40
52
  _init: function() {
41
53
  var self = this;
42
54
 
43
- if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend'))) {
44
- this.$element.parent('.input-append, .input-prepend').find('.add-on').on({
55
+ if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-group') && this.$element.parent().hasClass('bootstrap-timepicker'))) {
56
+ this.$element.parent('.input-group.bootstrap-timepicker').find('.input-group-addon').on({
45
57
  'click.timepicker': $.proxy(this.showWidget, this)
46
58
  });
47
59
  this.$element.on({
@@ -120,7 +132,7 @@
120
132
  }
121
133
  } else {
122
134
  if (this.hour <= 0) {
123
- this.hour = this.maxHours;
135
+ this.hour = this.maxHours - 1;
124
136
  } else {
125
137
  this.hour--;
126
138
  }
@@ -156,14 +168,28 @@
156
168
  },
157
169
 
158
170
  elementKeydown: function(e) {
159
- switch (e.keyCode) {
171
+ switch (e.which) {
160
172
  case 9: //tab
173
+ if (e.shiftKey) {
174
+ if (this.highlightedUnit === 'hour') {
175
+ break;
176
+ }
177
+ this.highlightPrevUnit();
178
+ } else if ((this.showMeridian && this.highlightedUnit === 'meridian') || (this.showSeconds && this.highlightedUnit === 'second') || (!this.showMeridian && !this.showSeconds && this.highlightedUnit ==='minute')) {
179
+ break;
180
+ } else {
181
+ this.highlightNextUnit();
182
+ }
183
+ e.preventDefault();
184
+ this.updateFromElementVal();
185
+ break;
161
186
  case 27: // escape
162
187
  this.updateFromElementVal();
163
188
  break;
164
189
  case 37: // left arrow
165
190
  e.preventDefault();
166
191
  this.highlightPrevUnit();
192
+ this.updateFromElementVal();
167
193
  break;
168
194
  case 38: // up arrow
169
195
  e.preventDefault();
@@ -190,6 +216,7 @@
190
216
  case 39: // right arrow
191
217
  e.preventDefault();
192
218
  this.highlightNextUnit();
219
+ this.updateFromElementVal();
193
220
  break;
194
221
  case 40: // down arrow
195
222
  e.preventDefault();
@@ -349,7 +376,7 @@
349
376
  this.$widget.removeClass('open');
350
377
  }
351
378
 
352
- $(document).off('mousedown.timepicker, touchend.timepicker');
379
+ $(document).off('mousedown.timepicker, touchend.timepicker', this.handleDocumentClick);
353
380
 
354
381
  this.isOpen = false;
355
382
  // show/hide approach taken by datepicker
@@ -433,15 +460,15 @@
433
460
 
434
461
  this.highlightedUnit = 'hour';
435
462
 
436
- if ($element.setSelectionRange) {
437
- setTimeout(function() {
463
+ if ($element.setSelectionRange) {
464
+ setTimeout(function() {
438
465
  if (self.hour < 10) {
439
466
  $element.setSelectionRange(0,1);
440
467
  } else {
441
468
  $element.setSelectionRange(0,2);
442
469
  }
443
- }, 0);
444
- }
470
+ }, 0);
471
+ }
445
472
  },
446
473
 
447
474
  highlightMinute: function() {
@@ -450,15 +477,15 @@
450
477
 
451
478
  this.highlightedUnit = 'minute';
452
479
 
453
- if ($element.setSelectionRange) {
454
- setTimeout(function() {
480
+ if ($element.setSelectionRange) {
481
+ setTimeout(function() {
455
482
  if (self.hour < 10) {
456
483
  $element.setSelectionRange(2,4);
457
484
  } else {
458
485
  $element.setSelectionRange(3,5);
459
486
  }
460
- }, 0);
461
- }
487
+ }, 0);
488
+ }
462
489
  },
463
490
 
464
491
  highlightSecond: function() {
@@ -467,15 +494,15 @@
467
494
 
468
495
  this.highlightedUnit = 'second';
469
496
 
470
- if ($element.setSelectionRange) {
471
- setTimeout(function() {
497
+ if ($element.setSelectionRange) {
498
+ setTimeout(function() {
472
499
  if (self.hour < 10) {
473
500
  $element.setSelectionRange(5,7);
474
501
  } else {
475
502
  $element.setSelectionRange(6,8);
476
503
  }
477
- }, 0);
478
- }
504
+ }, 0);
505
+ }
479
506
  },
480
507
 
481
508
  highlightMeridian: function() {
@@ -484,25 +511,25 @@
484
511
 
485
512
  this.highlightedUnit = 'meridian';
486
513
 
487
- if ($element.setSelectionRange) {
488
- if (this.showSeconds) {
489
- setTimeout(function() {
514
+ if ($element.setSelectionRange) {
515
+ if (this.showSeconds) {
516
+ setTimeout(function() {
490
517
  if (self.hour < 10) {
491
518
  $element.setSelectionRange(8,10);
492
519
  } else {
493
520
  $element.setSelectionRange(9,11);
494
521
  }
495
- }, 0);
496
- } else {
497
- setTimeout(function() {
522
+ }, 0);
523
+ } else {
524
+ setTimeout(function() {
498
525
  if (self.hour < 10) {
499
526
  $element.setSelectionRange(5,7);
500
527
  } else {
501
528
  $element.setSelectionRange(6,8);
502
529
  }
503
- }, 0);
504
- }
505
- }
530
+ }, 0);
531
+ }
532
+ }
506
533
  },
507
534
 
508
535
  incrementHour: function() {
@@ -514,7 +541,7 @@
514
541
  this.hour = 0;
515
542
  }
516
543
  }
517
- if (this.hour === this.maxHours) {
544
+ if (this.hour === this.maxHours - 1) {
518
545
  this.hour = 0;
519
546
 
520
547
  return;
@@ -607,6 +634,23 @@
607
634
  return false;
608
635
  },
609
636
 
637
+ /**
638
+ * Given a segment value like 43, will round and snap the segment
639
+ * to the nearest "step", like 45 if step is 15. Segment will
640
+ * "overflow" to 0 if it's larger than 59 or would otherwise
641
+ * round up to 60.
642
+ */
643
+ changeToNearestStep: function (segment, step) {
644
+ if (segment % step === 0) {
645
+ return segment;
646
+ }
647
+ if (Math.round((segment % step) / step)) {
648
+ return (segment + (step - segment % step)) % 60;
649
+ } else {
650
+ return segment - segment % step;
651
+ }
652
+ },
653
+
610
654
  // This method was adapted from bootstrap-datepicker.
611
655
  place : function() {
612
656
  if (this.isInline) {
@@ -615,7 +659,7 @@
615
659
  var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth =
616
660
  $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop();
617
661
 
618
- var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10;
662
+ var zIndex = parseInt(this.$element.parents().filter(function() { return $(this).css('z-index') !== 'auto'; }).first().css('z-index'), 10) + 10;
619
663
  var offset = this.component ? this.component.parent().offset() : this.$element.offset();
620
664
  var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);
621
665
  var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);
@@ -735,7 +779,8 @@
735
779
  return;
736
780
  }
737
781
 
738
- var timeArray,
782
+ var timeMode,
783
+ timeArray,
739
784
  hour,
740
785
  minute,
741
786
  second,
@@ -759,34 +804,38 @@
759
804
  }
760
805
  }
761
806
  } else {
762
- if (time.match(/p/i) !== null) {
763
- meridian = 'PM';
764
- } else {
765
- meridian = 'AM';
807
+ timeMode = ((/a/i).test(time) ? 1 : 0) + ((/p/i).test(time) ? 2 : 0); // 0 = none, 1 = AM, 2 = PM, 3 = BOTH.
808
+ if (timeMode > 2) { // If both are present, fail.
809
+ this.clear();
810
+ return;
766
811
  }
767
812
 
768
- time = time.replace(/[^0-9\:]/g, '');
769
-
770
- timeArray = time.split(':');
813
+ timeArray = time.replace(/[^0-9\:]/g, '').split(':');
771
814
 
772
815
  hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
816
+
817
+ if(this.explicitMode && hour.length > 2 && (hour.length % 2) !== 0 ) {
818
+ this.clear();
819
+ return;
820
+ }
821
+
773
822
  minute = timeArray[1] ? timeArray[1].toString() : '';
774
823
  second = timeArray[2] ? timeArray[2].toString() : '';
775
824
 
776
- // idiot proofing
825
+ // adaptive time parsing
777
826
  if (hour.length > 4) {
778
- second = hour.substr(4, 2);
827
+ second = hour.slice(-2);
828
+ hour = hour.slice(0, -2);
779
829
  }
830
+
780
831
  if (hour.length > 2) {
781
- minute = hour.substr(2, 2);
782
- hour = hour.substr(0, 2);
832
+ minute = hour.slice(-2);
833
+ hour = hour.slice(0, -2);
783
834
  }
835
+
784
836
  if (minute.length > 2) {
785
- second = minute.substr(2, 2);
786
- minute = minute.substr(0, 2);
787
- }
788
- if (second.length > 2) {
789
- second = second.substr(2, 2);
837
+ second = minute.slice(-2);
838
+ minute = minute.slice(0, -2);
790
839
  }
791
840
 
792
841
  hour = parseInt(hour, 10);
@@ -803,43 +852,53 @@
803
852
  second = 0;
804
853
  }
805
854
 
806
- if (this.showMeridian) {
807
- if (hour < 1) {
808
- hour = 1;
809
- } else if (hour > 12) {
810
- hour = 12;
811
- }
812
- } else {
813
- if (hour > this.maxHours) {
814
- hour = this.maxHours;
815
- } else if (hour < 0) {
816
- hour = 0;
817
- }
818
- if (hour < 13 && meridian === 'PM') {
819
- hour = hour + 12;
820
- }
855
+ // Adjust the time based upon unit boundary.
856
+ // NOTE: Negatives will never occur due to time.replace() above.
857
+ if (second > 59) {
858
+ second = 59;
821
859
  }
822
860
 
823
- if (minute < 0) {
824
- minute = 0;
825
- } else if (minute >= 60) {
861
+ if (minute > 59) {
826
862
  minute = 59;
827
863
  }
828
864
 
829
- if (this.showSeconds) {
830
- if (isNaN(second)) {
831
- second = 0;
832
- } else if (second < 0) {
833
- second = 0;
834
- } else if (second >= 60) {
835
- second = 59;
865
+ if (hour >= this.maxHours) {
866
+ // No day/date handling.
867
+ hour = this.maxHours - 1;
868
+ }
869
+
870
+ if (this.showMeridian) {
871
+ if (hour > 12) {
872
+ // Force PM.
873
+ timeMode = 2;
874
+ hour -= 12;
875
+ }
876
+ if (!timeMode) {
877
+ timeMode = 1;
878
+ }
879
+ if (hour === 0) {
880
+ hour = 12; // AM or PM, reset to 12. 0 AM = 12 AM. 0 PM = 12 PM, etc.
881
+ }
882
+ meridian = timeMode === 1 ? 'AM' : 'PM';
883
+ } else if (hour < 12 && timeMode === 2) {
884
+ hour += 12;
885
+ } else {
886
+ if (hour >= this.maxHours) {
887
+ hour = this.maxHours - 1;
888
+ } else if (hour < 0) {
889
+ hour = 0;
836
890
  }
837
891
  }
838
892
  }
839
893
 
840
894
  this.hour = hour;
841
- this.minute = minute;
842
- this.second = second;
895
+ if (this.snapToStep) {
896
+ this.minute = this.changeToNearestStep(minute, this.minuteStep);
897
+ this.second = this.changeToNearestStep(second, this.secondStep);
898
+ } else {
899
+ this.minute = minute;
900
+ this.second = second;
901
+ }
843
902
  this.meridian = meridian;
844
903
 
845
904
  this.update(ignoreWidget);
@@ -856,16 +915,7 @@
856
915
 
857
916
  // show/hide approach taken by datepicker
858
917
  this.$widget.appendTo(this.appendWidgetTo);
859
- var self = this;
860
- $(document).on('mousedown.timepicker, touchend.timepicker', function (e) {
861
- // This condition was inspired by bootstrap-datepicker.
862
- // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
863
- if (!(self.$element.parent().find(e.target).length ||
864
- self.$widget.is(e.target) ||
865
- self.$widget.find(e.target).length)) {
866
- self.hideWidget();
867
- }
868
- });
918
+ $(document).on('mousedown.timepicker, touchend.timepicker', {scope: this}, this.handleDocumentClick);
869
919
 
870
920
  this.$element.trigger({
871
921
  'type': 'show.timepicker',
@@ -1000,9 +1050,13 @@
1000
1050
  var $input = $(e.target),
1001
1051
  name = $input.attr('class').replace('bootstrap-timepicker-', '');
1002
1052
 
1003
- switch (e.keyCode) {
1053
+ switch (e.which) {
1004
1054
  case 9: //tab
1005
- if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
1055
+ if (e.shiftKey) {
1056
+ if (name === 'hour') {
1057
+ return this.hideWidget();
1058
+ }
1059
+ } else if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
1006
1060
  return this.hideWidget();
1007
1061
  }
1008
1062
  break;
@@ -1051,7 +1105,7 @@
1051
1105
  },
1052
1106
 
1053
1107
  widgetKeyup: function(e) {
1054
- if ((e.keyCode === 65) || (e.keyCode === 77) || (e.keyCode === 80) || (e.keyCode === 46) || (e.keyCode === 8) || (e.keyCode >= 46 && e.keyCode <= 57) || (e.keyCode >= 96 && e.keyCode <= 105)) {
1108
+ if ((e.which === 65) || (e.which === 77) || (e.which === 80) || (e.which === 46) || (e.which === 8) || (e.which >= 48 && e.which <= 57) || (e.which >= 96 && e.which <= 105)) {
1055
1109
  this.updateFromWidgetInputs();
1056
1110
  }
1057
1111
  }
@@ -1085,13 +1139,15 @@
1085
1139
  modalBackdrop: false,
1086
1140
  orientation: { x: 'auto', y: 'auto'},
1087
1141
  secondStep: 15,
1142
+ snapToStep: false,
1088
1143
  showSeconds: false,
1089
1144
  showInputs: true,
1090
1145
  showMeridian: true,
1091
1146
  template: 'dropdown',
1092
1147
  appendWidgetTo: 'body',
1093
1148
  showWidgetOnAddonClick: true,
1094
- maxHours: 24
1149
+ maxHours: 24,
1150
+ explicitMode: false
1095
1151
  };
1096
1152
 
1097
1153
  $.fn.timepicker.Constructor = Timepicker;
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootstrap-timepicker-rails-addon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Yang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-22 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties