bootstrap-timepicker-rails-addon 0.1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # Bootstrap::Timepicker::Rails::Addon
2
+ This is the GEMified version of [bootstrap-timepicker](https://github.com/jdewit/bootstrap-timepicker)
3
+
4
+ bootstrap-timepicker-rails-addon project integrates Timepicker for Twitter Bootstrap 2.x with Rails 3 assets pipeline.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'bootstrap-timepicker-rails-addon'
11
+
12
+ Or you can install from latest build:
13
+
14
+ ```ruby
15
+ gem 'bootstrap-timepicker-rails-addon', :require => 'bootstrap-timepicker-rails-addon',
16
+ :git => 'git://github.com/ywjno/bootstrap-timepicker-rails-addon.git'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install bootstrap-timepicker-rails-addon
26
+
27
+ ## Usage
28
+
29
+ Add this line to app/assets/stylesheets/application.css
30
+
31
+ *= require bootstrap-timepicker
32
+
33
+ Add this line to app/assets/javascripts/application.js
34
+
35
+ //= require bootstrap-timepicker
36
+
37
+ Just call timepicker() with any selector in view.
38
+
39
+ ```javascript
40
+ $('#timepicker').timepicker();
41
+ ```
42
+
43
+ And here is the html code sample.
44
+
45
+ ```html
46
+ <div class="input-append bootstrap-timepicker">
47
+ <input id="timepicker" type="text" class="input-small">
48
+ <span class="add-on"><i class="icon-time"></i></span>
49
+ </div>
50
+ ```
51
+
52
+ Please view the bootstrap-timepicker <a href="http://jdewit.github.com/bootstrap-timepicker">demos & documentation</a>.
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ require "bootstrap-timepicker-rails-addon/version"
2
+
3
+ module Bootstrap
4
+ module Timepicker
5
+ module Rails
6
+ module Addon
7
+ class Engine < ::Rails::Engine
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Bootstrap
2
+ module Timepicker
3
+ module Rails
4
+ module Addon
5
+ VERSION = "0.1.1.2"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,883 @@
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 = '<input type="text" name="hour" class="bootstrap-timepicker-hour" maxlength="2"/>';
263
+ minuteTemplate = '<input type="text" name="minute" class="bootstrap-timepicker-minute" maxlength="2"/>';
264
+ secondTemplate = '<input type="text" name="second" class="bootstrap-timepicker-second" maxlength="2"/>';
265
+ meridianTemplate = '<input type="text" name="meridian" class="bootstrap-timepicker-meridian" maxlength="2"/>';
266
+ } else {
267
+ hourTemplate = '<span class="bootstrap-timepicker-hour"></span>';
268
+ minuteTemplate = '<span class="bootstrap-timepicker-minute"></span>';
269
+ secondTemplate = '<span class="bootstrap-timepicker-second"></span>';
270
+ meridianTemplate = '<span class="bootstrap-timepicker-meridian"></span>';
271
+ }
272
+
273
+ templateContent = '<table>'+
274
+ '<tr>'+
275
+ '<td><a href="#" data-action="incrementHour"><i class="icon-chevron-up"></i></a></td>'+
276
+ '<td class="separator">&nbsp;</td>'+
277
+ '<td><a href="#" data-action="incrementMinute"><i class="icon-chevron-up"></i></a></td>'+
278
+ (this.showSeconds ?
279
+ '<td class="separator">&nbsp;</td>'+
280
+ '<td><a href="#" data-action="incrementSecond"><i class="icon-chevron-up"></i></a></td>'
281
+ : '') +
282
+ (this.showMeridian ?
283
+ '<td class="separator">&nbsp;</td>'+
284
+ '<td class="meridian-column"><a href="#" data-action="toggleMeridian"><i class="icon-chevron-up"></i></a></td>'
285
+ : '') +
286
+ '</tr>'+
287
+ '<tr>'+
288
+ '<td>'+ hourTemplate +'</td> '+
289
+ '<td class="separator">:</td>'+
290
+ '<td>'+ minuteTemplate +'</td> '+
291
+ (this.showSeconds ?
292
+ '<td class="separator">:</td>'+
293
+ '<td>'+ secondTemplate +'</td>'
294
+ : '') +
295
+ (this.showMeridian ?
296
+ '<td class="separator">&nbsp;</td>'+
297
+ '<td>'+ meridianTemplate +'</td>'
298
+ : '') +
299
+ '</tr>'+
300
+ '<tr>'+
301
+ '<td><a href="#" data-action="decrementHour"><i class="icon-chevron-down"></i></a></td>'+
302
+ '<td class="separator"></td>'+
303
+ '<td><a href="#" data-action="decrementMinute"><i class="icon-chevron-down"></i></a></td>'+
304
+ (this.showSeconds ?
305
+ '<td class="separator">&nbsp;</td>'+
306
+ '<td><a href="#" data-action="decrementSecond"><i class="icon-chevron-down"></i></a></td>'
307
+ : '') +
308
+ (this.showMeridian ?
309
+ '<td class="separator">&nbsp;</td>'+
310
+ '<td><a href="#" data-action="toggleMeridian"><i class="icon-chevron-down"></i></a></td>'
311
+ : '') +
312
+ '</tr>'+
313
+ '</table>';
314
+
315
+ switch(this.template) {
316
+ case 'modal':
317
+ template = '<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="'+ (this.modalBackdrop ? 'true' : 'false') +'">'+
318
+ '<div class="modal-header">'+
319
+ '<a href="#" class="close" data-dismiss="modal">×</a>'+
320
+ '<h3>Pick a Time</h3>'+
321
+ '</div>'+
322
+ '<div class="modal-content">'+
323
+ templateContent +
324
+ '</div>'+
325
+ '<div class="modal-footer">'+
326
+ '<a href="#" class="btn btn-primary" data-dismiss="modal">OK</a>'+
327
+ '</div>'+
328
+ '</div>';
329
+ break;
330
+ case 'dropdown':
331
+ template = '<div class="bootstrap-timepicker-widget dropdown-menu">'+ templateContent +'</div>';
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);
@@ -0,0 +1,121 @@
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
+ .bootstrap-timepicker {
12
+ position: relative;
13
+ }
14
+ .bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu {
15
+ left: auto;
16
+ right: 0;
17
+ }
18
+ .bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before {
19
+ left: auto;
20
+ right: 12px;
21
+ }
22
+ .bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after {
23
+ left: auto;
24
+ right: 13px;
25
+ }
26
+ .bootstrap-timepicker .add-on {
27
+ cursor: pointer;
28
+ }
29
+ .bootstrap-timepicker .add-on i {
30
+ display: inline-block;
31
+ width: 16px;
32
+ height: 16px;
33
+ }
34
+ .bootstrap-timepicker-widget.dropdown-menu {
35
+ padding: 2px 3px 2px 2px;
36
+ }
37
+ .bootstrap-timepicker-widget.dropdown-menu.open {
38
+ display: inline-block;
39
+ }
40
+ .bootstrap-timepicker-widget.dropdown-menu:before {
41
+ border-bottom: 7px solid rgba(0, 0, 0, 0.2);
42
+ border-left: 7px solid transparent;
43
+ border-right: 7px solid transparent;
44
+ content: "";
45
+ display: inline-block;
46
+ left: 9px;
47
+ position: absolute;
48
+ top: -7px;
49
+ }
50
+ .bootstrap-timepicker-widget.dropdown-menu:after {
51
+ border-bottom: 6px solid #FFFFFF;
52
+ border-left: 6px solid transparent;
53
+ border-right: 6px solid transparent;
54
+ content: "";
55
+ display: inline-block;
56
+ left: 10px;
57
+ position: absolute;
58
+ top: -6px;
59
+ }
60
+ .bootstrap-timepicker-widget a.btn,
61
+ .bootstrap-timepicker-widget input {
62
+ border-radius: 4px;
63
+ }
64
+ .bootstrap-timepicker-widget table {
65
+ width: 100%;
66
+ margin: 0;
67
+ }
68
+ .bootstrap-timepicker-widget table td {
69
+ text-align: center;
70
+ height: 30px;
71
+ margin: 0;
72
+ padding: 2px;
73
+ }
74
+ .bootstrap-timepicker-widget table td:not(.separator) {
75
+ min-width: 30px;
76
+ }
77
+ .bootstrap-timepicker-widget table td span {
78
+ width: 100%;
79
+ }
80
+ .bootstrap-timepicker-widget table td a {
81
+ border: 1px transparent solid;
82
+ width: 100%;
83
+ display: inline-block;
84
+ margin: 0;
85
+ padding: 8px 0;
86
+ outline: 0;
87
+ color: #333;
88
+ }
89
+ .bootstrap-timepicker-widget table td a:hover {
90
+ text-decoration: none;
91
+ background-color: #eee;
92
+ -webkit-border-radius: 4px;
93
+ -moz-border-radius: 4px;
94
+ border-radius: 4px;
95
+ border-color: #ddd;
96
+ }
97
+ .bootstrap-timepicker-widget table td a i {
98
+ margin-top: 2px;
99
+ }
100
+ .bootstrap-timepicker-widget table td input {
101
+ width: 25px;
102
+ margin: 0;
103
+ text-align: center;
104
+ }
105
+ .bootstrap-timepicker-widget .modal-content {
106
+ padding: 4px;
107
+ }
108
+ @media (min-width: 767px) {
109
+ .bootstrap-timepicker-widget.modal {
110
+ width: 200px;
111
+ margin-left: -100px;
112
+ }
113
+ }
114
+ @media (max-width: 767px) {
115
+ .bootstrap-timepicker {
116
+ width: 100%;
117
+ }
118
+ .bootstrap-timepicker .dropdown-menu {
119
+ width: 100%;
120
+ }
121
+ }
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bootstrap-timepicker-rails-addon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Yang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: This gem provides bootstrap-timepicker.js and bootstrap-timepicker.css
63
+ for your Rails 3 application.
64
+ email:
65
+ - ywjno.dev@gmail.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/bootstrap-timepicker-rails-addon/version.rb
71
+ - lib/bootstrap-timepicker-rails-addon.rb
72
+ - vendor/assets/javascripts/bootstrap-timepicker.js
73
+ - vendor/assets/stylesheets/bootstrap-timepicker.css
74
+ - LICENSE
75
+ - README.md
76
+ homepage: https://github.com/ywjno/bootstrap-timepicker-rails-addon
77
+ licenses: []
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 1.8.24
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Use bootstrap-timepicker with Rails 3
100
+ test_files: []
101
+ has_rdoc: