bootstrap-timepicker-rails-addon 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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