bootstrap-timepicker-rails-addon 0.2.6.1 → 0.2.6.2

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: 2694f17a4761a18db42b46d55b1e867026cb02a9
4
- data.tar.gz: ea62c8d055d8687161a0bfcee2c06517f6ba7ecf
3
+ metadata.gz: 73ef986c743ddd07b6efa2abc64c65c3f9888b49
4
+ data.tar.gz: e7303c0b0db59c96dd3c51fa9e426b00b321d52d
5
5
  SHA512:
6
- metadata.gz: 2d2e5e51de5a3d959da06b06a28ded6c35cc7cf135199b0b624b25e5bd81a44d139f13f9dd94595568230476ae481343d12699aba2d1ee44250daef3aea593f5
7
- data.tar.gz: f7e42492cc187d4f02f1427c3ad1469d574b9b4caf78142ec8e1e925938ec3f18dafd3a1af51fa2dd8a95c6ca53b5bfda7f118cb59c9dd16ebb57461b2cf0438
6
+ metadata.gz: c71615436357e27de40230de0cc7ddf2a8d6cf8ae3dae38aad63159aaac6a489494f6c51db06e8228c4e94dcc6c6d15373f234f2e824d160da3555a2d47364c6
7
+ data.tar.gz: 0ffdef80c3570637f38f65cbe6e370c9c8bfbf4a84f7f0ebf30df64515c5b0fbde1b0938bb371a93a716481db6ce14f4af704ebb2a6d9af9a5f3e23959f35ac6
data/LICENSE CHANGED
@@ -1,22 +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.
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 CHANGED
@@ -1,62 +1,62 @@
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 and 4 assets pipeline.
5
-
6
- ## Installation
7
-
8
- Add this line to your application's Gemfile:
9
-
10
- gem 'bootstrap-sass', '~> 2.3.2.0'
11
- gem 'bootstrap-timepicker-rails-addon'
12
-
13
- Or you can install from latest build:
14
-
15
- ```ruby
16
- gem 'bootstrap-sass', '~> 2.3.2.0'
17
- gem 'bootstrap-timepicker-rails-addon', :require => 'bootstrap-timepicker-rails-addon',
18
- :git => 'git://github.com/ywjno/bootstrap-timepicker-rails-addon.git'
19
- ```
20
-
21
- And then execute:
22
-
23
- $ bundle
24
-
25
- Or install it yourself as:
26
-
27
- $ gem install bootstrap-timepicker-rails-addon
28
-
29
- ## Usage
30
-
31
- Add this line to app/assets/javascripts/application.js
32
-
33
- //= require bootstrap-timepicker
34
-
35
- Add this line to app/assets/stylesheets/application.css
36
-
37
- *= require bootstrap-timepicker
38
-
39
- Just call timepicker() with any selector in view.
40
-
41
- ```javascript
42
- $('#timepicker').timepicker();
43
- ```
44
-
45
- And here is the html code sample.
46
-
47
- ```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>
51
- </div>
52
- ```
53
-
54
- Please view the bootstrap-timepicker <a href="http://jdewit.github.io/bootstrap-timepicker/">demos & documentation</a>.
55
-
56
- ## Contributing
57
-
58
- 1. Fork it
59
- 2. Create your feature branch (`git checkout -b my-new-feature`)
60
- 3. Commit your changes (`git commit -am 'Add some feature'`)
61
- 4. Push to the branch (`git push origin my-new-feature`)
62
- 5. Create new Pull Request
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 and 4 assets pipeline.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'bootstrap-sass', '~> 2.3.2.0'
11
+ gem 'bootstrap-timepicker-rails-addon'
12
+
13
+ Or you can install from latest build:
14
+
15
+ ```ruby
16
+ gem 'bootstrap-sass', '~> 2.3.2.0'
17
+ gem 'bootstrap-timepicker-rails-addon', :require => 'bootstrap-timepicker-rails-addon',
18
+ :git => 'git://github.com/ywjno/bootstrap-timepicker-rails-addon.git'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install bootstrap-timepicker-rails-addon
28
+
29
+ ## Usage
30
+
31
+ Add this line to app/assets/javascripts/application.js
32
+
33
+ //= require bootstrap-timepicker
34
+
35
+ Add this line to app/assets/stylesheets/application.css
36
+
37
+ *= require bootstrap-timepicker
38
+
39
+ Just call timepicker() with any selector in view.
40
+
41
+ ```javascript
42
+ $('#timepicker').timepicker();
43
+ ```
44
+
45
+ And here is the html code sample.
46
+
47
+ ```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>
51
+ </div>
52
+ ```
53
+
54
+ Please view the bootstrap-timepicker <a href="http://jdewit.github.io/bootstrap-timepicker/">demos & documentation</a>.
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
@@ -1,12 +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
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
@@ -1,9 +1,9 @@
1
- module Bootstrap
2
- module Timepicker
3
- module Rails
4
- module Addon
5
- VERSION = "0.2.6.1"
6
- end
7
- end
8
- end
9
- end
1
+ module Bootstrap
2
+ module Timepicker
3
+ module Rails
4
+ module Addon
5
+ VERSION = "0.2.6.2"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,1097 +1,1111 @@
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
- 'use strict';
13
-
14
- // TIMEPICKER PUBLIC CLASS DEFINITION
15
- var Timepicker = function(element, options) {
16
- this.widget = '';
17
- this.$element = $(element);
18
- this.defaultTime = options.defaultTime;
19
- this.disableFocus = options.disableFocus;
20
- this.disableMousewheel = options.disableMousewheel;
21
- this.isOpen = options.isOpen;
22
- this.minuteStep = options.minuteStep;
23
- this.modalBackdrop = options.modalBackdrop;
24
- this.orientation = options.orientation;
25
- this.secondStep = options.secondStep;
26
- this.showInputs = options.showInputs;
27
- this.showMeridian = options.showMeridian;
28
- this.showSeconds = options.showSeconds;
29
- this.template = options.template;
30
- this.appendWidgetTo = options.appendWidgetTo;
31
- this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;
32
-
33
- this._init();
34
- };
35
-
36
- Timepicker.prototype = {
37
-
38
- constructor: Timepicker,
39
- _init: function() {
40
- var self = this;
41
-
42
- if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend'))) {
43
- this.$element.parent('.input-append, .input-prepend').find('.add-on').on({
44
- 'click.timepicker': $.proxy(this.showWidget, this)
45
- });
46
- this.$element.on({
47
- 'focus.timepicker': $.proxy(this.highlightUnit, this),
48
- 'click.timepicker': $.proxy(this.highlightUnit, this),
49
- 'keydown.timepicker': $.proxy(this.elementKeydown, this),
50
- 'blur.timepicker': $.proxy(this.blurElement, this),
51
- 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
52
- });
53
- } else {
54
- if (this.template) {
55
- this.$element.on({
56
- 'focus.timepicker': $.proxy(this.showWidget, this),
57
- 'click.timepicker': $.proxy(this.showWidget, this),
58
- 'blur.timepicker': $.proxy(this.blurElement, this),
59
- 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
60
- });
61
- } else {
62
- this.$element.on({
63
- 'focus.timepicker': $.proxy(this.highlightUnit, this),
64
- 'click.timepicker': $.proxy(this.highlightUnit, this),
65
- 'keydown.timepicker': $.proxy(this.elementKeydown, this),
66
- 'blur.timepicker': $.proxy(this.blurElement, this),
67
- 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
68
- });
69
- }
70
- }
71
-
72
- if (this.template !== false) {
73
- this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this));
74
- } else {
75
- this.$widget = false;
76
- }
77
-
78
- if (this.showInputs && this.$widget !== false) {
79
- this.$widget.find('input').each(function() {
80
- $(this).on({
81
- 'click.timepicker': function() { $(this).select(); },
82
- 'keydown.timepicker': $.proxy(self.widgetKeydown, self),
83
- 'keyup.timepicker': $.proxy(self.widgetKeyup, self)
84
- });
85
- });
86
- }
87
-
88
- this.setDefaultTime(this.defaultTime);
89
- },
90
-
91
- blurElement: function() {
92
- this.highlightedUnit = null;
93
- this.updateFromElementVal();
94
- },
95
-
96
- clear: function() {
97
- this.hour = '';
98
- this.minute = '';
99
- this.second = '';
100
- this.meridian = '';
101
-
102
- this.$element.val('');
103
- },
104
-
105
- decrementHour: function() {
106
- if (this.showMeridian) {
107
- if (this.hour === 1) {
108
- this.hour = 12;
109
- } else if (this.hour === 12) {
110
- this.hour--;
111
-
112
- return this.toggleMeridian();
113
- } else if (this.hour === 0) {
114
- this.hour = 11;
115
-
116
- return this.toggleMeridian();
117
- } else {
118
- this.hour--;
119
- }
120
- } else {
121
- if (this.hour <= 0) {
122
- this.hour = 23;
123
- } else {
124
- this.hour--;
125
- }
126
- }
127
- },
128
-
129
- decrementMinute: function(step) {
130
- var newVal;
131
-
132
- if (step) {
133
- newVal = this.minute - step;
134
- } else {
135
- newVal = this.minute - this.minuteStep;
136
- }
137
-
138
- if (newVal < 0) {
139
- this.decrementHour();
140
- this.minute = newVal + 60;
141
- } else {
142
- this.minute = newVal;
143
- }
144
- },
145
-
146
- decrementSecond: function() {
147
- var newVal = this.second - this.secondStep;
148
-
149
- if (newVal < 0) {
150
- this.decrementMinute(true);
151
- this.second = newVal + 60;
152
- } else {
153
- this.second = newVal;
154
- }
155
- },
156
-
157
- elementKeydown: function(e) {
158
- switch (e.keyCode) {
159
- case 9: //tab
160
- case 27: // escape
161
- this.updateFromElementVal();
162
- break;
163
- case 37: // left arrow
164
- e.preventDefault();
165
- this.highlightPrevUnit();
166
- break;
167
- case 38: // up arrow
168
- e.preventDefault();
169
- switch (this.highlightedUnit) {
170
- case 'hour':
171
- this.incrementHour();
172
- this.highlightHour();
173
- break;
174
- case 'minute':
175
- this.incrementMinute();
176
- this.highlightMinute();
177
- break;
178
- case 'second':
179
- this.incrementSecond();
180
- this.highlightSecond();
181
- break;
182
- case 'meridian':
183
- this.toggleMeridian();
184
- this.highlightMeridian();
185
- break;
186
- }
187
- this.update();
188
- break;
189
- case 39: // right arrow
190
- e.preventDefault();
191
- this.highlightNextUnit();
192
- break;
193
- case 40: // down arrow
194
- e.preventDefault();
195
- switch (this.highlightedUnit) {
196
- case 'hour':
197
- this.decrementHour();
198
- this.highlightHour();
199
- break;
200
- case 'minute':
201
- this.decrementMinute();
202
- this.highlightMinute();
203
- break;
204
- case 'second':
205
- this.decrementSecond();
206
- this.highlightSecond();
207
- break;
208
- case 'meridian':
209
- this.toggleMeridian();
210
- this.highlightMeridian();
211
- break;
212
- }
213
-
214
- this.update();
215
- break;
216
- }
217
- },
218
-
219
- getCursorPosition: function() {
220
- var input = this.$element.get(0);
221
-
222
- if ('selectionStart' in input) {// Standard-compliant browsers
223
-
224
- return input.selectionStart;
225
- } else if (document.selection) {// IE fix
226
- input.focus();
227
- var sel = document.selection.createRange(),
228
- selLen = document.selection.createRange().text.length;
229
-
230
- sel.moveStart('character', - input.value.length);
231
-
232
- return sel.text.length - selLen;
233
- }
234
- },
235
-
236
- getTemplate: function() {
237
- var template,
238
- hourTemplate,
239
- minuteTemplate,
240
- secondTemplate,
241
- meridianTemplate,
242
- templateContent;
243
-
244
- if (this.showInputs) {
245
- hourTemplate = '<input type="text" class="bootstrap-timepicker-hour" maxlength="2"/>';
246
- minuteTemplate = '<input type="text" class="bootstrap-timepicker-minute" maxlength="2"/>';
247
- secondTemplate = '<input type="text" class="bootstrap-timepicker-second" maxlength="2"/>';
248
- meridianTemplate = '<input type="text" class="bootstrap-timepicker-meridian" maxlength="2"/>';
249
- } else {
250
- hourTemplate = '<span class="bootstrap-timepicker-hour"></span>';
251
- minuteTemplate = '<span class="bootstrap-timepicker-minute"></span>';
252
- secondTemplate = '<span class="bootstrap-timepicker-second"></span>';
253
- meridianTemplate = '<span class="bootstrap-timepicker-meridian"></span>';
254
- }
255
-
256
- templateContent = '<table>'+
257
- '<tr>'+
258
- '<td><a href="#" data-action="incrementHour"><i class="icon-chevron-up"></i></a></td>'+
259
- '<td class="separator">&nbsp;</td>'+
260
- '<td><a href="#" data-action="incrementMinute"><i class="icon-chevron-up"></i></a></td>'+
261
- (this.showSeconds ?
262
- '<td class="separator">&nbsp;</td>'+
263
- '<td><a href="#" data-action="incrementSecond"><i class="icon-chevron-up"></i></a></td>'
264
- : '') +
265
- (this.showMeridian ?
266
- '<td class="separator">&nbsp;</td>'+
267
- '<td class="meridian-column"><a href="#" data-action="toggleMeridian"><i class="icon-chevron-up"></i></a></td>'
268
- : '') +
269
- '</tr>'+
270
- '<tr>'+
271
- '<td>'+ hourTemplate +'</td> '+
272
- '<td class="separator">:</td>'+
273
- '<td>'+ minuteTemplate +'</td> '+
274
- (this.showSeconds ?
275
- '<td class="separator">:</td>'+
276
- '<td>'+ secondTemplate +'</td>'
277
- : '') +
278
- (this.showMeridian ?
279
- '<td class="separator">&nbsp;</td>'+
280
- '<td>'+ meridianTemplate +'</td>'
281
- : '') +
282
- '</tr>'+
283
- '<tr>'+
284
- '<td><a href="#" data-action="decrementHour"><i class="icon-chevron-down"></i></a></td>'+
285
- '<td class="separator"></td>'+
286
- '<td><a href="#" data-action="decrementMinute"><i class="icon-chevron-down"></i></a></td>'+
287
- (this.showSeconds ?
288
- '<td class="separator">&nbsp;</td>'+
289
- '<td><a href="#" data-action="decrementSecond"><i class="icon-chevron-down"></i></a></td>'
290
- : '') +
291
- (this.showMeridian ?
292
- '<td class="separator">&nbsp;</td>'+
293
- '<td><a href="#" data-action="toggleMeridian"><i class="icon-chevron-down"></i></a></td>'
294
- : '') +
295
- '</tr>'+
296
- '</table>';
297
-
298
- switch(this.template) {
299
- case 'modal':
300
- template = '<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="'+ (this.modalBackdrop ? 'true' : 'false') +'">'+
301
- '<div class="modal-header">'+
302
- '<a href="#" class="close" data-dismiss="modal">×</a>'+
303
- '<h3>Pick a Time</h3>'+
304
- '</div>'+
305
- '<div class="modal-content">'+
306
- templateContent +
307
- '</div>'+
308
- '<div class="modal-footer">'+
309
- '<a href="#" class="btn btn-primary" data-dismiss="modal">OK</a>'+
310
- '</div>'+
311
- '</div>';
312
- break;
313
- case 'dropdown':
314
- template = '<div class="bootstrap-timepicker-widget dropdown-menu">'+ templateContent +'</div>';
315
- break;
316
- }
317
-
318
- return template;
319
- },
320
-
321
- getTime: function() {
322
- if (this.hour === '') {
323
- return '';
324
- }
325
-
326
- return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : '');
327
- },
328
-
329
- hideWidget: function() {
330
- if (this.isOpen === false) {
331
- return;
332
- }
333
-
334
- this.$element.trigger({
335
- 'type': 'hide.timepicker',
336
- 'time': {
337
- 'value': this.getTime(),
338
- 'hours': this.hour,
339
- 'minutes': this.minute,
340
- 'seconds': this.second,
341
- 'meridian': this.meridian
342
- }
343
- });
344
-
345
- if (this.template === 'modal' && this.$widget.modal) {
346
- this.$widget.modal('hide');
347
- } else {
348
- this.$widget.removeClass('open');
349
- }
350
-
351
- $(document).off('mousedown.timepicker, touchend.timepicker');
352
-
353
- this.isOpen = false;
354
- // show/hide approach taken by datepicker
355
- this.$widget.detach();
356
- },
357
-
358
- highlightUnit: function() {
359
- this.position = this.getCursorPosition();
360
- if (this.position >= 0 && this.position <= 2) {
361
- this.highlightHour();
362
- } else if (this.position >= 3 && this.position <= 5) {
363
- this.highlightMinute();
364
- } else if (this.position >= 6 && this.position <= 8) {
365
- if (this.showSeconds) {
366
- this.highlightSecond();
367
- } else {
368
- this.highlightMeridian();
369
- }
370
- } else if (this.position >= 9 && this.position <= 11) {
371
- this.highlightMeridian();
372
- }
373
- },
374
-
375
- highlightNextUnit: function() {
376
- switch (this.highlightedUnit) {
377
- case 'hour':
378
- this.highlightMinute();
379
- break;
380
- case 'minute':
381
- if (this.showSeconds) {
382
- this.highlightSecond();
383
- } else if (this.showMeridian){
384
- this.highlightMeridian();
385
- } else {
386
- this.highlightHour();
387
- }
388
- break;
389
- case 'second':
390
- if (this.showMeridian) {
391
- this.highlightMeridian();
392
- } else {
393
- this.highlightHour();
394
- }
395
- break;
396
- case 'meridian':
397
- this.highlightHour();
398
- break;
399
- }
400
- },
401
-
402
- highlightPrevUnit: function() {
403
- switch (this.highlightedUnit) {
404
- case 'hour':
405
- if(this.showMeridian){
406
- this.highlightMeridian();
407
- } else if (this.showSeconds) {
408
- this.highlightSecond();
409
- } else {
410
- this.highlightMinute();
411
- }
412
- break;
413
- case 'minute':
414
- this.highlightHour();
415
- break;
416
- case 'second':
417
- this.highlightMinute();
418
- break;
419
- case 'meridian':
420
- if (this.showSeconds) {
421
- this.highlightSecond();
422
- } else {
423
- this.highlightMinute();
424
- }
425
- break;
426
- }
427
- },
428
-
429
- highlightHour: function() {
430
- var $element = this.$element.get(0),
431
- self = this;
432
-
433
- this.highlightedUnit = 'hour';
434
-
435
- if ($element.setSelectionRange) {
436
- setTimeout(function() {
437
- if (self.hour < 10) {
438
- $element.setSelectionRange(0,1);
439
- } else {
440
- $element.setSelectionRange(0,2);
441
- }
442
- }, 0);
443
- }
444
- },
445
-
446
- highlightMinute: function() {
447
- var $element = this.$element.get(0),
448
- self = this;
449
-
450
- this.highlightedUnit = 'minute';
451
-
452
- if ($element.setSelectionRange) {
453
- setTimeout(function() {
454
- if (self.hour < 10) {
455
- $element.setSelectionRange(2,4);
456
- } else {
457
- $element.setSelectionRange(3,5);
458
- }
459
- }, 0);
460
- }
461
- },
462
-
463
- highlightSecond: function() {
464
- var $element = this.$element.get(0),
465
- self = this;
466
-
467
- this.highlightedUnit = 'second';
468
-
469
- if ($element.setSelectionRange) {
470
- setTimeout(function() {
471
- if (self.hour < 10) {
472
- $element.setSelectionRange(5,7);
473
- } else {
474
- $element.setSelectionRange(6,8);
475
- }
476
- }, 0);
477
- }
478
- },
479
-
480
- highlightMeridian: function() {
481
- var $element = this.$element.get(0),
482
- self = this;
483
-
484
- this.highlightedUnit = 'meridian';
485
-
486
- if ($element.setSelectionRange) {
487
- if (this.showSeconds) {
488
- setTimeout(function() {
489
- if (self.hour < 10) {
490
- $element.setSelectionRange(8,10);
491
- } else {
492
- $element.setSelectionRange(9,11);
493
- }
494
- }, 0);
495
- } else {
496
- setTimeout(function() {
497
- if (self.hour < 10) {
498
- $element.setSelectionRange(5,7);
499
- } else {
500
- $element.setSelectionRange(6,8);
501
- }
502
- }, 0);
503
- }
504
- }
505
- },
506
-
507
- incrementHour: function() {
508
- if (this.showMeridian) {
509
- if (this.hour === 11) {
510
- this.hour++;
511
- return this.toggleMeridian();
512
- } else if (this.hour === 12) {
513
- this.hour = 0;
514
- }
515
- }
516
- if (this.hour === 23) {
517
- this.hour = 0;
518
-
519
- return;
520
- }
521
- this.hour++;
522
- },
523
-
524
- incrementMinute: function(step) {
525
- var newVal;
526
-
527
- if (step) {
528
- newVal = this.minute + step;
529
- } else {
530
- newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep);
531
- }
532
-
533
- if (newVal > 59) {
534
- this.incrementHour();
535
- this.minute = newVal - 60;
536
- } else {
537
- this.minute = newVal;
538
- }
539
- },
540
-
541
- incrementSecond: function() {
542
- var newVal = this.second + this.secondStep - (this.second % this.secondStep);
543
-
544
- if (newVal > 59) {
545
- this.incrementMinute(true);
546
- this.second = newVal - 60;
547
- } else {
548
- this.second = newVal;
549
- }
550
- },
551
-
552
- mousewheel: function(e) {
553
- if (this.disableMousewheel) {
554
- return;
555
- }
556
-
557
- e.preventDefault();
558
- e.stopPropagation();
559
-
560
- var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail,
561
- scrollTo = null;
562
-
563
- if (e.type === 'mousewheel') {
564
- scrollTo = (e.originalEvent.wheelDelta * -1);
565
- }
566
- else if (e.type === 'DOMMouseScroll') {
567
- scrollTo = 40 * e.originalEvent.detail;
568
- }
569
-
570
- if (scrollTo) {
571
- e.preventDefault();
572
- $(this).scrollTop(scrollTo + $(this).scrollTop());
573
- }
574
-
575
- switch (this.highlightedUnit) {
576
- case 'minute':
577
- if (delta > 0) {
578
- this.incrementMinute();
579
- } else {
580
- this.decrementMinute();
581
- }
582
- this.highlightMinute();
583
- break;
584
- case 'second':
585
- if (delta > 0) {
586
- this.incrementSecond();
587
- } else {
588
- this.decrementSecond();
589
- }
590
- this.highlightSecond();
591
- break;
592
- case 'meridian':
593
- this.toggleMeridian();
594
- this.highlightMeridian();
595
- break;
596
- default:
597
- if (delta > 0) {
598
- this.incrementHour();
599
- } else {
600
- this.decrementHour();
601
- }
602
- this.highlightHour();
603
- break;
604
- }
605
-
606
- return false;
607
- },
608
-
609
- // This method was adapted from bootstrap-datepicker.
610
- place : function() {
611
- if (this.isInline) {
612
- return;
613
- }
614
- var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth =
615
- $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop();
616
-
617
- var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10;
618
- var offset = this.component ? this.component.parent().offset() : this.$element.offset();
619
- var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);
620
- var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);
621
- var left = offset.left, top = offset.top;
622
-
623
- this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left');
624
-
625
- if (this.orientation.x !== 'auto') {
626
- this.picker.addClass('datepicker-orient-' + this.orientation.x);
627
- if (this.orientation.x === 'right') {
628
- left -= widgetWidth - width;
629
- }
630
- } else{
631
- // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways
632
- // Default to left
633
- this.$widget.addClass('timepicker-orient-left');
634
- if (offset.left < 0) {
635
- left -= offset.left - visualPadding;
636
- } else if (offset.left + widgetWidth > windowWidth) {
637
- left = windowWidth - widgetWidth - visualPadding;
638
- }
639
- }
640
- // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget
641
- var yorient = this.orientation.y, topOverflow, bottomOverflow;
642
- if (yorient === 'auto') {
643
- topOverflow = -scrollTop + offset.top - widgetHeight;
644
- bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight);
645
- if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) {
646
- yorient = 'top';
647
- } else {
648
- yorient = 'bottom';
649
- }
650
- }
651
- this.$widget.addClass('timepicker-orient-' + yorient);
652
- if (yorient === 'top'){
653
- top += height;
654
- } else{
655
- top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10);
656
- }
657
-
658
- this.$widget.css({
659
- top : top,
660
- left : left,
661
- zIndex : zIndex
662
- });
663
- },
664
-
665
- remove: function() {
666
- $('document').off('.timepicker');
667
- if (this.$widget) {
668
- this.$widget.remove();
669
- }
670
- delete this.$element.data().timepicker;
671
- },
672
-
673
- setDefaultTime: function(defaultTime) {
674
- if (!this.$element.val()) {
675
- if (defaultTime === 'current') {
676
- var dTime = new Date(),
677
- hours = dTime.getHours(),
678
- minutes = dTime.getMinutes(),
679
- seconds = dTime.getSeconds(),
680
- meridian = 'AM';
681
-
682
- if (seconds !== 0) {
683
- seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep;
684
- if (seconds === 60) {
685
- minutes += 1;
686
- seconds = 0;
687
- }
688
- }
689
-
690
- if (minutes !== 0) {
691
- minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep;
692
- if (minutes === 60) {
693
- hours += 1;
694
- minutes = 0;
695
- }
696
- }
697
-
698
- if (this.showMeridian) {
699
- if (hours === 0) {
700
- hours = 12;
701
- } else if (hours >= 12) {
702
- if (hours > 12) {
703
- hours = hours - 12;
704
- }
705
- meridian = 'PM';
706
- } else {
707
- meridian = 'AM';
708
- }
709
- }
710
-
711
- this.hour = hours;
712
- this.minute = minutes;
713
- this.second = seconds;
714
- this.meridian = meridian;
715
-
716
- this.update();
717
-
718
- } else if (defaultTime === false) {
719
- this.hour = 0;
720
- this.minute = 0;
721
- this.second = 0;
722
- this.meridian = 'AM';
723
- } else {
724
- this.setTime(defaultTime);
725
- }
726
- } else {
727
- this.updateFromElementVal();
728
- }
729
- },
730
-
731
- setTime: function(time, ignoreWidget) {
732
- if (!time) {
733
- this.clear();
734
- return;
735
- }
736
-
737
- var timeArray,
738
- hour,
739
- minute,
740
- second,
741
- meridian;
742
-
743
- if (typeof time === 'object' && time.getMonth){
744
- // this is a date object
745
- hour = time.getHours();
746
- minute = time.getMinutes();
747
- second = time.getSeconds();
748
-
749
- if (this.showMeridian){
750
- meridian = 'AM';
751
- if (hour > 12){
752
- meridian = 'PM';
753
- hour = hour % 12;
754
- }
755
-
756
- if (hour === 12){
757
- meridian = 'PM';
758
- }
759
- }
760
- } else {
761
- if (time.match(/p/i) !== null) {
762
- meridian = 'PM';
763
- } else {
764
- meridian = 'AM';
765
- }
766
-
767
- time = time.replace(/[^0-9\:]/g, '');
768
-
769
- timeArray = time.split(':');
770
-
771
- hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
772
- minute = timeArray[1] ? timeArray[1].toString() : '';
773
- second = timeArray[2] ? timeArray[2].toString() : '';
774
-
775
- // idiot proofing
776
- if (hour.length > 4) {
777
- second = hour.substr(4, 2);
778
- }
779
- if (hour.length > 2) {
780
- minute = hour.substr(2, 2);
781
- hour = hour.substr(0, 2);
782
- }
783
- if (minute.length > 2) {
784
- second = minute.substr(2, 2);
785
- minute = minute.substr(0, 2);
786
- }
787
- if (second.length > 2) {
788
- second = second.substr(2, 2);
789
- }
790
-
791
- hour = parseInt(hour, 10);
792
- minute = parseInt(minute, 10);
793
- second = parseInt(second, 10);
794
-
795
- if (isNaN(hour)) {
796
- hour = 0;
797
- }
798
- if (isNaN(minute)) {
799
- minute = 0;
800
- }
801
- if (isNaN(second)) {
802
- second = 0;
803
- }
804
-
805
- if (this.showMeridian) {
806
- if (hour < 1) {
807
- hour = 1;
808
- } else if (hour > 12) {
809
- hour = 12;
810
- }
811
- } else {
812
- if (hour >= 24) {
813
- hour = 23;
814
- } else if (hour < 0) {
815
- hour = 0;
816
- }
817
- if (hour < 13 && meridian === 'PM') {
818
- hour = hour + 12;
819
- }
820
- }
821
-
822
- if (minute < 0) {
823
- minute = 0;
824
- } else if (minute >= 60) {
825
- minute = 59;
826
- }
827
-
828
- if (this.showSeconds) {
829
- if (isNaN(second)) {
830
- second = 0;
831
- } else if (second < 0) {
832
- second = 0;
833
- } else if (second >= 60) {
834
- second = 59;
835
- }
836
- }
837
- }
838
-
839
- this.hour = hour;
840
- this.minute = minute;
841
- this.second = second;
842
- this.meridian = meridian;
843
-
844
- this.update(ignoreWidget);
845
- },
846
-
847
- showWidget: function() {
848
- if (this.isOpen) {
849
- return;
850
- }
851
-
852
- if (this.$element.is(':disabled')) {
853
- return;
854
- }
855
-
856
- // show/hide approach taken by datepicker
857
- this.$widget.appendTo(this.appendWidgetTo);
858
- var self = this;
859
- $(document).on('mousedown.timepicker, touchend.timepicker', function (e) {
860
- // This condition was inspired by bootstrap-datepicker.
861
- // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
862
- if (!(self.$element.parent().find(e.target).length ||
863
- self.$widget.is(e.target) ||
864
- self.$widget.find(e.target).length)) {
865
- self.hideWidget();
866
- }
867
- });
868
-
869
- this.$element.trigger({
870
- 'type': 'show.timepicker',
871
- 'time': {
872
- 'value': this.getTime(),
873
- 'hours': this.hour,
874
- 'minutes': this.minute,
875
- 'seconds': this.second,
876
- 'meridian': this.meridian
877
- }
878
- });
879
-
880
- this.place();
881
- if (this.disableFocus) {
882
- this.$element.blur();
883
- }
884
-
885
- // widget shouldn't be empty on open
886
- if (this.hour === '') {
887
- if (this.defaultTime) {
888
- this.setDefaultTime(this.defaultTime);
889
- } else {
890
- this.setTime('0:0:0');
891
- }
892
- }
893
-
894
- if (this.template === 'modal' && this.$widget.modal) {
895
- this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this));
896
- } else {
897
- if (this.isOpen === false) {
898
- this.$widget.addClass('open');
899
- }
900
- }
901
-
902
- this.isOpen = true;
903
- },
904
-
905
- toggleMeridian: function() {
906
- this.meridian = this.meridian === 'AM' ? 'PM' : 'AM';
907
- },
908
-
909
- update: function(ignoreWidget) {
910
- this.updateElement();
911
- if (!ignoreWidget) {
912
- this.updateWidget();
913
- }
914
-
915
- this.$element.trigger({
916
- 'type': 'changeTime.timepicker',
917
- 'time': {
918
- 'value': this.getTime(),
919
- 'hours': this.hour,
920
- 'minutes': this.minute,
921
- 'seconds': this.second,
922
- 'meridian': this.meridian
923
- }
924
- });
925
- },
926
-
927
- updateElement: function() {
928
- this.$element.val(this.getTime()).change();
929
- },
930
-
931
- updateFromElementVal: function() {
932
- this.setTime(this.$element.val());
933
- },
934
-
935
- updateWidget: function() {
936
- if (this.$widget === false) {
937
- return;
938
- }
939
-
940
- var hour = this.hour,
941
- minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute,
942
- second = this.second.toString().length === 1 ? '0' + this.second : this.second;
943
-
944
- if (this.showInputs) {
945
- this.$widget.find('input.bootstrap-timepicker-hour').val(hour);
946
- this.$widget.find('input.bootstrap-timepicker-minute').val(minute);
947
-
948
- if (this.showSeconds) {
949
- this.$widget.find('input.bootstrap-timepicker-second').val(second);
950
- }
951
- if (this.showMeridian) {
952
- this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian);
953
- }
954
- } else {
955
- this.$widget.find('span.bootstrap-timepicker-hour').text(hour);
956
- this.$widget.find('span.bootstrap-timepicker-minute').text(minute);
957
-
958
- if (this.showSeconds) {
959
- this.$widget.find('span.bootstrap-timepicker-second').text(second);
960
- }
961
- if (this.showMeridian) {
962
- this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian);
963
- }
964
- }
965
- },
966
-
967
- updateFromWidgetInputs: function() {
968
- if (this.$widget === false) {
969
- return;
970
- }
971
-
972
- var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' +
973
- this.$widget.find('input.bootstrap-timepicker-minute').val() +
974
- (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') +
975
- (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '')
976
- ;
977
-
978
- this.setTime(t, true);
979
- },
980
-
981
- widgetClick: function(e) {
982
- e.stopPropagation();
983
- e.preventDefault();
984
-
985
- var $input = $(e.target),
986
- action = $input.closest('a').data('action');
987
-
988
- if (action) {
989
- this[action]();
990
- }
991
- this.update();
992
-
993
- if ($input.is('input')) {
994
- $input.get(0).setSelectionRange(0,2);
995
- }
996
- },
997
-
998
- widgetKeydown: function(e) {
999
- var $input = $(e.target),
1000
- name = $input.attr('class').replace('bootstrap-timepicker-', '');
1001
-
1002
- switch (e.keyCode) {
1003
- case 9: //tab
1004
- if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
1005
- return this.hideWidget();
1006
- }
1007
- break;
1008
- case 27: // escape
1009
- this.hideWidget();
1010
- break;
1011
- case 38: // up arrow
1012
- e.preventDefault();
1013
- switch (name) {
1014
- case 'hour':
1015
- this.incrementHour();
1016
- break;
1017
- case 'minute':
1018
- this.incrementMinute();
1019
- break;
1020
- case 'second':
1021
- this.incrementSecond();
1022
- break;
1023
- case 'meridian':
1024
- this.toggleMeridian();
1025
- break;
1026
- }
1027
- this.setTime(this.getTime());
1028
- $input.get(0).setSelectionRange(0,2);
1029
- break;
1030
- case 40: // down arrow
1031
- e.preventDefault();
1032
- switch (name) {
1033
- case 'hour':
1034
- this.decrementHour();
1035
- break;
1036
- case 'minute':
1037
- this.decrementMinute();
1038
- break;
1039
- case 'second':
1040
- this.decrementSecond();
1041
- break;
1042
- case 'meridian':
1043
- this.toggleMeridian();
1044
- break;
1045
- }
1046
- this.setTime(this.getTime());
1047
- $input.get(0).setSelectionRange(0,2);
1048
- break;
1049
- }
1050
- },
1051
-
1052
- widgetKeyup: function(e) {
1053
- if ((e.keyCode === 65) || (e.keyCode === 77) || (e.keyCode === 80) || (e.keyCode === 46) || (e.keyCode === 8) || (e.keyCode >= 46 && e.keyCode <= 57)) {
1054
- this.updateFromWidgetInputs();
1055
- }
1056
- }
1057
- };
1058
-
1059
- //TIMEPICKER PLUGIN DEFINITION
1060
- $.fn.timepicker = function(option) {
1061
- var args = Array.apply(null, arguments);
1062
- args.shift();
1063
- return this.each(function() {
1064
- var $this = $(this),
1065
- data = $this.data('timepicker'),
1066
- options = typeof option === 'object' && option;
1067
-
1068
- if (!data) {
1069
- $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data()))));
1070
- }
1071
-
1072
- if (typeof option === 'string') {
1073
- data[option].apply(data, args);
1074
- }
1075
- });
1076
- };
1077
-
1078
- $.fn.timepicker.defaults = {
1079
- defaultTime: 'current',
1080
- disableFocus: false,
1081
- disableMousewheel: false,
1082
- isOpen: false,
1083
- minuteStep: 15,
1084
- modalBackdrop: false,
1085
- orientation: { x: 'auto', y: 'auto'},
1086
- secondStep: 15,
1087
- showSeconds: false,
1088
- showInputs: true,
1089
- showMeridian: true,
1090
- template: 'dropdown',
1091
- appendWidgetTo: 'body',
1092
- showWidgetOnAddonClick: true
1093
- };
1094
-
1095
- $.fn.timepicker.Constructor = Timepicker;
1096
-
1097
- })(jQuery, window, document);
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
+ 'use strict';
13
+
14
+ // TIMEPICKER PUBLIC CLASS DEFINITION
15
+ var Timepicker = function(element, options) {
16
+ this.widget = '';
17
+ this.$element = $(element);
18
+ this.defaultTime = options.defaultTime;
19
+ this.disableFocus = options.disableFocus;
20
+ this.disableMousewheel = options.disableMousewheel;
21
+ this.isOpen = options.isOpen;
22
+ this.minuteStep = options.minuteStep;
23
+ this.modalBackdrop = options.modalBackdrop;
24
+ this.orientation = options.orientation;
25
+ this.secondStep = options.secondStep;
26
+ this.showInputs = options.showInputs;
27
+ this.showMeridian = options.showMeridian;
28
+ this.showSeconds = options.showSeconds;
29
+ this.template = options.template;
30
+ this.appendWidgetTo = options.appendWidgetTo;
31
+ this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;
32
+
33
+ this._init();
34
+ };
35
+
36
+ Timepicker.prototype = {
37
+
38
+ constructor: Timepicker,
39
+ _init: function() {
40
+ var self = this;
41
+
42
+ if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend'))) {
43
+ this.$element.parent('.input-append, .input-prepend').find('.add-on').on({
44
+ 'click.timepicker': $.proxy(this.showWidget, this)
45
+ });
46
+ this.$element.on({
47
+ 'focus.timepicker': $.proxy(this.highlightUnit, this),
48
+ 'click.timepicker': $.proxy(this.highlightUnit, this),
49
+ 'keydown.timepicker': $.proxy(this.elementKeydown, this),
50
+ 'blur.timepicker': $.proxy(this.blurElement, this),
51
+ 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
52
+ });
53
+ } else {
54
+ if (this.template) {
55
+ this.$element.on({
56
+ 'focus.timepicker': $.proxy(this.showWidget, this),
57
+ 'click.timepicker': $.proxy(this.showWidget, this),
58
+ 'blur.timepicker': $.proxy(this.blurElement, this),
59
+ 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
60
+ });
61
+ } else {
62
+ this.$element.on({
63
+ 'focus.timepicker': $.proxy(this.highlightUnit, this),
64
+ 'click.timepicker': $.proxy(this.highlightUnit, this),
65
+ 'keydown.timepicker': $.proxy(this.elementKeydown, this),
66
+ 'blur.timepicker': $.proxy(this.blurElement, this),
67
+ 'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
68
+ });
69
+ }
70
+ }
71
+
72
+ if (this.template !== false) {
73
+ this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this));
74
+ } else {
75
+ this.$widget = false;
76
+ }
77
+
78
+ if (this.showInputs && this.$widget !== false) {
79
+ this.$widget.find('input').each(function() {
80
+ $(this).on({
81
+ 'click.timepicker': function() { $(this).select(); },
82
+ 'keydown.timepicker': $.proxy(self.widgetKeydown, self),
83
+ 'keyup.timepicker': $.proxy(self.widgetKeyup, self)
84
+ });
85
+ });
86
+ }
87
+
88
+ this.setDefaultTime(this.defaultTime);
89
+ },
90
+
91
+ blurElement: function() {
92
+ this.highlightedUnit = null;
93
+ this.updateFromElementVal();
94
+ },
95
+
96
+ clear: function() {
97
+ this.hour = '';
98
+ this.minute = '';
99
+ this.second = '';
100
+ this.meridian = '';
101
+
102
+ this.$element.val('');
103
+ },
104
+
105
+ decrementHour: function() {
106
+ if (this.showMeridian) {
107
+ if (this.hour === 1) {
108
+ this.hour = 12;
109
+ } else if (this.hour === 12) {
110
+ this.hour--;
111
+
112
+ return this.toggleMeridian();
113
+ } else if (this.hour === 0) {
114
+ this.hour = 11;
115
+
116
+ return this.toggleMeridian();
117
+ } else {
118
+ this.hour--;
119
+ }
120
+ } else {
121
+ if (this.hour <= 0) {
122
+ this.hour = 23;
123
+ } else {
124
+ this.hour--;
125
+ }
126
+ }
127
+ },
128
+
129
+ decrementMinute: function(step) {
130
+ var newVal;
131
+
132
+ if (step) {
133
+ newVal = this.minute - step;
134
+ } else {
135
+ newVal = this.minute - this.minuteStep;
136
+ }
137
+
138
+ if (newVal < 0) {
139
+ this.decrementHour();
140
+ this.minute = newVal + 60;
141
+ } else {
142
+ this.minute = newVal;
143
+ }
144
+ },
145
+
146
+ decrementSecond: function() {
147
+ var newVal = this.second - this.secondStep;
148
+
149
+ if (newVal < 0) {
150
+ this.decrementMinute(true);
151
+ this.second = newVal + 60;
152
+ } else {
153
+ this.second = newVal;
154
+ }
155
+ },
156
+
157
+ elementKeydown: function(e) {
158
+ switch (e.keyCode) {
159
+ case 9: //tab
160
+ case 27: // escape
161
+ this.updateFromElementVal();
162
+ break;
163
+ case 37: // left arrow
164
+ e.preventDefault();
165
+ this.highlightPrevUnit();
166
+ break;
167
+ case 38: // up arrow
168
+ e.preventDefault();
169
+ switch (this.highlightedUnit) {
170
+ case 'hour':
171
+ this.incrementHour();
172
+ this.highlightHour();
173
+ break;
174
+ case 'minute':
175
+ this.incrementMinute();
176
+ this.highlightMinute();
177
+ break;
178
+ case 'second':
179
+ this.incrementSecond();
180
+ this.highlightSecond();
181
+ break;
182
+ case 'meridian':
183
+ this.toggleMeridian();
184
+ this.highlightMeridian();
185
+ break;
186
+ }
187
+ this.update();
188
+ break;
189
+ case 39: // right arrow
190
+ e.preventDefault();
191
+ this.highlightNextUnit();
192
+ break;
193
+ case 40: // down arrow
194
+ e.preventDefault();
195
+ switch (this.highlightedUnit) {
196
+ case 'hour':
197
+ this.decrementHour();
198
+ this.highlightHour();
199
+ break;
200
+ case 'minute':
201
+ this.decrementMinute();
202
+ this.highlightMinute();
203
+ break;
204
+ case 'second':
205
+ this.decrementSecond();
206
+ this.highlightSecond();
207
+ break;
208
+ case 'meridian':
209
+ this.toggleMeridian();
210
+ this.highlightMeridian();
211
+ break;
212
+ }
213
+
214
+ this.update();
215
+ break;
216
+ }
217
+ },
218
+
219
+ getCursorPosition: function() {
220
+ var input = this.$element.get(0);
221
+
222
+ if ('selectionStart' in input) {// Standard-compliant browsers
223
+
224
+ return input.selectionStart;
225
+ } else if (document.selection) {// IE fix
226
+ input.focus();
227
+ var sel = document.selection.createRange(),
228
+ selLen = document.selection.createRange().text.length;
229
+
230
+ sel.moveStart('character', - input.value.length);
231
+
232
+ return sel.text.length - selLen;
233
+ }
234
+ },
235
+
236
+ getTemplate: function() {
237
+ var template,
238
+ hourTemplate,
239
+ minuteTemplate,
240
+ secondTemplate,
241
+ meridianTemplate,
242
+ templateContent;
243
+
244
+ if (this.showInputs) {
245
+ hourTemplate = '<input type="text" class="bootstrap-timepicker-hour" maxlength="2"/>';
246
+ minuteTemplate = '<input type="text" class="bootstrap-timepicker-minute" maxlength="2"/>';
247
+ secondTemplate = '<input type="text" class="bootstrap-timepicker-second" maxlength="2"/>';
248
+ meridianTemplate = '<input type="text" class="bootstrap-timepicker-meridian" maxlength="2"/>';
249
+ } else {
250
+ hourTemplate = '<span class="bootstrap-timepicker-hour"></span>';
251
+ minuteTemplate = '<span class="bootstrap-timepicker-minute"></span>';
252
+ secondTemplate = '<span class="bootstrap-timepicker-second"></span>';
253
+ meridianTemplate = '<span class="bootstrap-timepicker-meridian"></span>';
254
+ }
255
+
256
+ templateContent = '<table>'+
257
+ '<tr>'+
258
+ '<td><a href="#" data-action="incrementHour"><i class="icon-chevron-up"></i></a></td>'+
259
+ '<td class="separator">&nbsp;</td>'+
260
+ '<td><a href="#" data-action="incrementMinute"><i class="icon-chevron-up"></i></a></td>'+
261
+ (this.showSeconds ?
262
+ '<td class="separator">&nbsp;</td>'+
263
+ '<td><a href="#" data-action="incrementSecond"><i class="icon-chevron-up"></i></a></td>'
264
+ : '') +
265
+ (this.showMeridian ?
266
+ '<td class="separator">&nbsp;</td>'+
267
+ '<td class="meridian-column"><a href="#" data-action="toggleMeridian"><i class="icon-chevron-up"></i></a></td>'
268
+ : '') +
269
+ '</tr>'+
270
+ '<tr>'+
271
+ '<td>'+ hourTemplate +'</td> '+
272
+ '<td class="separator">:</td>'+
273
+ '<td>'+ minuteTemplate +'</td> '+
274
+ (this.showSeconds ?
275
+ '<td class="separator">:</td>'+
276
+ '<td>'+ secondTemplate +'</td>'
277
+ : '') +
278
+ (this.showMeridian ?
279
+ '<td class="separator">&nbsp;</td>'+
280
+ '<td>'+ meridianTemplate +'</td>'
281
+ : '') +
282
+ '</tr>'+
283
+ '<tr>'+
284
+ '<td><a href="#" data-action="decrementHour"><i class="icon-chevron-down"></i></a></td>'+
285
+ '<td class="separator"></td>'+
286
+ '<td><a href="#" data-action="decrementMinute"><i class="icon-chevron-down"></i></a></td>'+
287
+ (this.showSeconds ?
288
+ '<td class="separator">&nbsp;</td>'+
289
+ '<td><a href="#" data-action="decrementSecond"><i class="icon-chevron-down"></i></a></td>'
290
+ : '') +
291
+ (this.showMeridian ?
292
+ '<td class="separator">&nbsp;</td>'+
293
+ '<td><a href="#" data-action="toggleMeridian"><i class="icon-chevron-down"></i></a></td>'
294
+ : '') +
295
+ '</tr>'+
296
+ '</table>';
297
+
298
+ switch(this.template) {
299
+ case 'modal':
300
+ template = '<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="'+ (this.modalBackdrop ? 'true' : 'false') +'">'+
301
+ '<div class="modal-header">'+
302
+ '<a href="#" class="close" data-dismiss="modal">×</a>'+
303
+ '<h3>Pick a Time</h3>'+
304
+ '</div>'+
305
+ '<div class="modal-content">'+
306
+ templateContent +
307
+ '</div>'+
308
+ '<div class="modal-footer">'+
309
+ '<a href="#" class="btn btn-primary" data-dismiss="modal">OK</a>'+
310
+ '</div>'+
311
+ '</div>';
312
+ break;
313
+ case 'dropdown':
314
+ template = '<div class="bootstrap-timepicker-widget dropdown-menu">'+ templateContent +'</div>';
315
+ break;
316
+ }
317
+
318
+ return template;
319
+ },
320
+
321
+ getTime: function() {
322
+ if (this.hour === '') {
323
+ return '';
324
+ }
325
+
326
+ return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : '');
327
+ },
328
+
329
+ hideWidget: function() {
330
+ if (this.isOpen === false) {
331
+ return;
332
+ }
333
+
334
+ this.$element.trigger({
335
+ 'type': 'hide.timepicker',
336
+ 'time': {
337
+ 'value': this.getTime(),
338
+ 'hours': this.hour,
339
+ 'minutes': this.minute,
340
+ 'seconds': this.second,
341
+ 'meridian': this.meridian
342
+ }
343
+ });
344
+
345
+ if (this.template === 'modal' && this.$widget.modal) {
346
+ this.$widget.modal('hide');
347
+ } else {
348
+ this.$widget.removeClass('open');
349
+ }
350
+
351
+ $(document).off('mousedown.timepicker, touchend.timepicker');
352
+
353
+ this.isOpen = false;
354
+ // show/hide approach taken by datepicker
355
+ this.$widget.detach();
356
+ },
357
+
358
+ highlightUnit: function() {
359
+ this.position = this.getCursorPosition();
360
+ if (this.position >= 0 && this.position <= 2) {
361
+ this.highlightHour();
362
+ } else if (this.position >= 3 && this.position <= 5) {
363
+ this.highlightMinute();
364
+ } else if (this.position >= 6 && this.position <= 8) {
365
+ if (this.showSeconds) {
366
+ this.highlightSecond();
367
+ } else {
368
+ this.highlightMeridian();
369
+ }
370
+ } else if (this.position >= 9 && this.position <= 11) {
371
+ this.highlightMeridian();
372
+ }
373
+ },
374
+
375
+ highlightNextUnit: function() {
376
+ switch (this.highlightedUnit) {
377
+ case 'hour':
378
+ this.highlightMinute();
379
+ break;
380
+ case 'minute':
381
+ if (this.showSeconds) {
382
+ this.highlightSecond();
383
+ } else if (this.showMeridian){
384
+ this.highlightMeridian();
385
+ } else {
386
+ this.highlightHour();
387
+ }
388
+ break;
389
+ case 'second':
390
+ if (this.showMeridian) {
391
+ this.highlightMeridian();
392
+ } else {
393
+ this.highlightHour();
394
+ }
395
+ break;
396
+ case 'meridian':
397
+ this.highlightHour();
398
+ break;
399
+ }
400
+ },
401
+
402
+ highlightPrevUnit: function() {
403
+ switch (this.highlightedUnit) {
404
+ case 'hour':
405
+ if(this.showMeridian){
406
+ this.highlightMeridian();
407
+ } else if (this.showSeconds) {
408
+ this.highlightSecond();
409
+ } else {
410
+ this.highlightMinute();
411
+ }
412
+ break;
413
+ case 'minute':
414
+ this.highlightHour();
415
+ break;
416
+ case 'second':
417
+ this.highlightMinute();
418
+ break;
419
+ case 'meridian':
420
+ if (this.showSeconds) {
421
+ this.highlightSecond();
422
+ } else {
423
+ this.highlightMinute();
424
+ }
425
+ break;
426
+ }
427
+ },
428
+
429
+ highlightHour: function() {
430
+ var $element = this.$element.get(0),
431
+ self = this;
432
+
433
+ this.highlightedUnit = 'hour';
434
+
435
+ if ($element.setSelectionRange) {
436
+ setTimeout(function() {
437
+ if (self.hour < 10) {
438
+ $element.setSelectionRange(0,1);
439
+ } else {
440
+ $element.setSelectionRange(0,2);
441
+ }
442
+ }, 0);
443
+ }
444
+ },
445
+
446
+ highlightMinute: function() {
447
+ var $element = this.$element.get(0),
448
+ self = this;
449
+
450
+ this.highlightedUnit = 'minute';
451
+
452
+ if ($element.setSelectionRange) {
453
+ setTimeout(function() {
454
+ if (self.hour < 10) {
455
+ $element.setSelectionRange(2,4);
456
+ } else {
457
+ $element.setSelectionRange(3,5);
458
+ }
459
+ }, 0);
460
+ }
461
+ },
462
+
463
+ highlightSecond: function() {
464
+ var $element = this.$element.get(0),
465
+ self = this;
466
+
467
+ this.highlightedUnit = 'second';
468
+
469
+ if ($element.setSelectionRange) {
470
+ setTimeout(function() {
471
+ if (self.hour < 10) {
472
+ $element.setSelectionRange(5,7);
473
+ } else {
474
+ $element.setSelectionRange(6,8);
475
+ }
476
+ }, 0);
477
+ }
478
+ },
479
+
480
+ highlightMeridian: function() {
481
+ var $element = this.$element.get(0),
482
+ self = this;
483
+
484
+ this.highlightedUnit = 'meridian';
485
+
486
+ if ($element.setSelectionRange) {
487
+ if (this.showSeconds) {
488
+ setTimeout(function() {
489
+ if (self.hour < 10) {
490
+ $element.setSelectionRange(8,10);
491
+ } else {
492
+ $element.setSelectionRange(9,11);
493
+ }
494
+ }, 0);
495
+ } else {
496
+ setTimeout(function() {
497
+ if (self.hour < 10) {
498
+ $element.setSelectionRange(5,7);
499
+ } else {
500
+ $element.setSelectionRange(6,8);
501
+ }
502
+ }, 0);
503
+ }
504
+ }
505
+ },
506
+
507
+ incrementHour: function() {
508
+ if (this.showMeridian) {
509
+ if (this.hour === 11) {
510
+ this.hour++;
511
+ return this.toggleMeridian();
512
+ } else if (this.hour === 12) {
513
+ this.hour = 0;
514
+ }
515
+ }
516
+ if (this.hour === 23) {
517
+ this.hour = 0;
518
+
519
+ return;
520
+ }
521
+ this.hour++;
522
+ },
523
+
524
+ incrementMinute: function(step) {
525
+ var newVal;
526
+
527
+ if (step) {
528
+ newVal = this.minute + step;
529
+ } else {
530
+ newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep);
531
+ }
532
+
533
+ if (newVal > 59) {
534
+ this.incrementHour();
535
+ this.minute = newVal - 60;
536
+ } else {
537
+ this.minute = newVal;
538
+ }
539
+ },
540
+
541
+ incrementSecond: function() {
542
+ var newVal = this.second + this.secondStep - (this.second % this.secondStep);
543
+
544
+ if (newVal > 59) {
545
+ this.incrementMinute(true);
546
+ this.second = newVal - 60;
547
+ } else {
548
+ this.second = newVal;
549
+ }
550
+ },
551
+
552
+ mousewheel: function(e) {
553
+ if (this.disableMousewheel) {
554
+ return;
555
+ }
556
+
557
+ e.preventDefault();
558
+ e.stopPropagation();
559
+
560
+ var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail,
561
+ scrollTo = null;
562
+
563
+ if (e.type === 'mousewheel') {
564
+ scrollTo = (e.originalEvent.wheelDelta * -1);
565
+ }
566
+ else if (e.type === 'DOMMouseScroll') {
567
+ scrollTo = 40 * e.originalEvent.detail;
568
+ }
569
+
570
+ if (scrollTo) {
571
+ e.preventDefault();
572
+ $(this).scrollTop(scrollTo + $(this).scrollTop());
573
+ }
574
+
575
+ switch (this.highlightedUnit) {
576
+ case 'minute':
577
+ if (delta > 0) {
578
+ this.incrementMinute();
579
+ } else {
580
+ this.decrementMinute();
581
+ }
582
+ this.highlightMinute();
583
+ break;
584
+ case 'second':
585
+ if (delta > 0) {
586
+ this.incrementSecond();
587
+ } else {
588
+ this.decrementSecond();
589
+ }
590
+ this.highlightSecond();
591
+ break;
592
+ case 'meridian':
593
+ this.toggleMeridian();
594
+ this.highlightMeridian();
595
+ break;
596
+ default:
597
+ if (delta > 0) {
598
+ this.incrementHour();
599
+ } else {
600
+ this.decrementHour();
601
+ }
602
+ this.highlightHour();
603
+ break;
604
+ }
605
+
606
+ return false;
607
+ },
608
+
609
+ // This method was adapted from bootstrap-datepicker.
610
+ place : function() {
611
+ if (this.isInline) {
612
+ return;
613
+ }
614
+ var widgetWidth = this.$widget.outerWidth(), widgetHeight = this.$widget.outerHeight(), visualPadding = 10, windowWidth =
615
+ $(window).width(), windowHeight = $(window).height(), scrollTop = $(window).scrollTop();
616
+
617
+ var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10;
618
+ var offset = this.component ? this.component.parent().offset() : this.$element.offset();
619
+ var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);
620
+ var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);
621
+ var left = offset.left, top = offset.top;
622
+
623
+ this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left');
624
+
625
+ if (this.orientation.x !== 'auto') {
626
+ this.picker.addClass('datepicker-orient-' + this.orientation.x);
627
+ if (this.orientation.x === 'right') {
628
+ left -= widgetWidth - width;
629
+ }
630
+ } else{
631
+ // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways
632
+ // Default to left
633
+ this.$widget.addClass('timepicker-orient-left');
634
+ if (offset.left < 0) {
635
+ left -= offset.left - visualPadding;
636
+ } else if (offset.left + widgetWidth > windowWidth) {
637
+ left = windowWidth - widgetWidth - visualPadding;
638
+ }
639
+ }
640
+ // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget
641
+ var yorient = this.orientation.y, topOverflow, bottomOverflow;
642
+ if (yorient === 'auto') {
643
+ topOverflow = -scrollTop + offset.top - widgetHeight;
644
+ bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight);
645
+ if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) {
646
+ yorient = 'top';
647
+ } else {
648
+ yorient = 'bottom';
649
+ }
650
+ }
651
+ this.$widget.addClass('timepicker-orient-' + yorient);
652
+ if (yorient === 'top'){
653
+ top += height;
654
+ } else{
655
+ top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10);
656
+ }
657
+
658
+ this.$widget.css({
659
+ top : top,
660
+ left : left,
661
+ zIndex : zIndex
662
+ });
663
+ },
664
+
665
+ remove: function() {
666
+ $('document').off('.timepicker');
667
+ if (this.$widget) {
668
+ this.$widget.remove();
669
+ }
670
+ delete this.$element.data().timepicker;
671
+ },
672
+
673
+ setDefaultTime: function(defaultTime) {
674
+ if (!this.$element.val()) {
675
+ if (defaultTime === 'current') {
676
+ var dTime = new Date(),
677
+ hours = dTime.getHours(),
678
+ minutes = dTime.getMinutes(),
679
+ seconds = dTime.getSeconds(),
680
+ meridian = 'AM';
681
+
682
+ if (seconds !== 0) {
683
+ seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep;
684
+ if (seconds === 60) {
685
+ minutes += 1;
686
+ seconds = 0;
687
+ }
688
+ }
689
+
690
+ if (minutes !== 0) {
691
+ minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep;
692
+ if (minutes === 60) {
693
+ hours += 1;
694
+ minutes = 0;
695
+ }
696
+ }
697
+
698
+ if (this.showMeridian) {
699
+ if (hours === 0) {
700
+ hours = 12;
701
+ } else if (hours >= 12) {
702
+ if (hours > 12) {
703
+ hours = hours - 12;
704
+ }
705
+ meridian = 'PM';
706
+ } else {
707
+ meridian = 'AM';
708
+ }
709
+ }
710
+
711
+ this.hour = hours;
712
+ this.minute = minutes;
713
+ this.second = seconds;
714
+ this.meridian = meridian;
715
+
716
+ this.update();
717
+
718
+ } else if (defaultTime === false) {
719
+ this.hour = 0;
720
+ this.minute = 0;
721
+ this.second = 0;
722
+ this.meridian = 'AM';
723
+ } else {
724
+ this.setTime(defaultTime);
725
+ }
726
+ } else {
727
+ this.updateFromElementVal();
728
+ }
729
+ },
730
+
731
+ setTime: function(time, ignoreWidget) {
732
+ if (!time) {
733
+ this.clear();
734
+ return;
735
+ }
736
+
737
+ var timeArray,
738
+ hour,
739
+ minute,
740
+ second,
741
+ meridian;
742
+
743
+ if (typeof time === 'object' && time.getMonth){
744
+ // this is a date object
745
+ hour = time.getHours();
746
+ minute = time.getMinutes();
747
+ second = time.getSeconds();
748
+
749
+ if (this.showMeridian){
750
+ meridian = 'AM';
751
+ if (hour > 12){
752
+ meridian = 'PM';
753
+ hour = hour % 12;
754
+ }
755
+
756
+ if (hour === 12){
757
+ meridian = 'PM';
758
+ }
759
+ }
760
+ } else {
761
+ if (time.match(/p/i) !== null) {
762
+ meridian = 'PM';
763
+ } else {
764
+ meridian = 'AM';
765
+ }
766
+
767
+ time = time.replace(/[^0-9\:]/g, '');
768
+
769
+ timeArray = time.split(':');
770
+
771
+ hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
772
+ minute = timeArray[1] ? timeArray[1].toString() : '';
773
+ second = timeArray[2] ? timeArray[2].toString() : '';
774
+
775
+ // idiot proofing
776
+ if (hour.length > 4) {
777
+ second = hour.substr(4, 2);
778
+ }
779
+ if (hour.length > 2) {
780
+ minute = hour.substr(2, 2);
781
+ hour = hour.substr(0, 2);
782
+ }
783
+ if (minute.length > 2) {
784
+ second = minute.substr(2, 2);
785
+ minute = minute.substr(0, 2);
786
+ }
787
+ if (second.length > 2) {
788
+ second = second.substr(2, 2);
789
+ }
790
+
791
+ hour = parseInt(hour, 10);
792
+ minute = parseInt(minute, 10);
793
+ second = parseInt(second, 10);
794
+
795
+ if (isNaN(hour)) {
796
+ hour = 0;
797
+ }
798
+ if (isNaN(minute)) {
799
+ minute = 0;
800
+ }
801
+ if (isNaN(second)) {
802
+ second = 0;
803
+ }
804
+
805
+ if (this.showMeridian) {
806
+ if (hour < 1) {
807
+ hour = 1;
808
+ } else if (hour > 12) {
809
+ hour = 12;
810
+ }
811
+ } else {
812
+ if (hour >= 24) {
813
+ hour = 23;
814
+ } else if (hour < 0) {
815
+ hour = 0;
816
+ }
817
+ if (hour < 13 && meridian === 'PM') {
818
+ hour = hour + 12;
819
+ }
820
+ }
821
+
822
+ if (minute < 0) {
823
+ minute = 0;
824
+ } else if (minute >= 60) {
825
+ minute = 59;
826
+ }
827
+
828
+ if (this.showSeconds) {
829
+ if (isNaN(second)) {
830
+ second = 0;
831
+ } else if (second < 0) {
832
+ second = 0;
833
+ } else if (second >= 60) {
834
+ second = 59;
835
+ }
836
+ }
837
+ }
838
+
839
+ this.hour = hour;
840
+ this.minute = minute;
841
+ this.second = second;
842
+ this.meridian = meridian;
843
+
844
+ this.update(ignoreWidget);
845
+ },
846
+
847
+ showWidget: function() {
848
+ if (this.isOpen) {
849
+ return;
850
+ }
851
+
852
+ if (this.$element.is(':disabled')) {
853
+ return;
854
+ }
855
+
856
+ // show/hide approach taken by datepicker
857
+ this.$widget.appendTo(this.appendWidgetTo);
858
+ var self = this;
859
+ $(document).on('mousedown.timepicker, touchend.timepicker', function (e) {
860
+ // This condition was inspired by bootstrap-datepicker.
861
+ // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
862
+ if (!(self.$element.parent().find(e.target).length ||
863
+ self.$widget.is(e.target) ||
864
+ self.$widget.find(e.target).length)) {
865
+ self.hideWidget();
866
+ }
867
+ });
868
+
869
+ this.$element.trigger({
870
+ 'type': 'show.timepicker',
871
+ 'time': {
872
+ 'value': this.getTime(),
873
+ 'hours': this.hour,
874
+ 'minutes': this.minute,
875
+ 'seconds': this.second,
876
+ 'meridian': this.meridian
877
+ }
878
+ });
879
+
880
+ this.place();
881
+ if (this.disableFocus) {
882
+ this.$element.blur();
883
+ }
884
+
885
+ // widget shouldn't be empty on open
886
+ if (this.hour === '') {
887
+ if (this.defaultTime) {
888
+ this.setDefaultTime(this.defaultTime);
889
+ } else {
890
+ this.setTime('0:0:0');
891
+ }
892
+ }
893
+
894
+ if (this.template === 'modal' && this.$widget.modal) {
895
+ this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this));
896
+ } else {
897
+ if (this.isOpen === false) {
898
+ this.$widget.addClass('open');
899
+ }
900
+ }
901
+
902
+ this.isOpen = true;
903
+ },
904
+
905
+ toggleMeridian: function() {
906
+ this.meridian = this.meridian === 'AM' ? 'PM' : 'AM';
907
+ },
908
+
909
+ update: function(ignoreWidget) {
910
+ this.updateElement();
911
+ if (!ignoreWidget) {
912
+ this.updateWidget();
913
+ }
914
+
915
+ this.$element.trigger({
916
+ 'type': 'changeTime.timepicker',
917
+ 'time': {
918
+ 'value': this.getTime(),
919
+ 'hours': this.hour,
920
+ 'minutes': this.minute,
921
+ 'seconds': this.second,
922
+ 'meridian': this.meridian
923
+ }
924
+ });
925
+ },
926
+
927
+ updateElement: function() {
928
+ this.$element.val(this.getTime()).change();
929
+ },
930
+
931
+ updateFromElementVal: function() {
932
+ this.setTime(this.$element.val());
933
+ },
934
+
935
+ updateWidget: function() {
936
+ if (this.$widget === false) {
937
+ return;
938
+ }
939
+
940
+ var hour = this.hour,
941
+ minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute,
942
+ second = this.second.toString().length === 1 ? '0' + this.second : this.second;
943
+
944
+ if (this.showInputs) {
945
+ this.$widget.find('input.bootstrap-timepicker-hour').val(hour);
946
+ this.$widget.find('input.bootstrap-timepicker-minute').val(minute);
947
+
948
+ if (this.showSeconds) {
949
+ this.$widget.find('input.bootstrap-timepicker-second').val(second);
950
+ }
951
+ if (this.showMeridian) {
952
+ this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian);
953
+ }
954
+ } else {
955
+ this.$widget.find('span.bootstrap-timepicker-hour').text(hour);
956
+ this.$widget.find('span.bootstrap-timepicker-minute').text(minute);
957
+
958
+ if (this.showSeconds) {
959
+ this.$widget.find('span.bootstrap-timepicker-second').text(second);
960
+ }
961
+ if (this.showMeridian) {
962
+ this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian);
963
+ }
964
+ }
965
+ },
966
+
967
+ updateFromWidgetInputs: function() {
968
+ if (this.$widget === false) {
969
+ return;
970
+ }
971
+
972
+ var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' +
973
+ this.$widget.find('input.bootstrap-timepicker-minute').val() +
974
+ (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') +
975
+ (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '')
976
+ ;
977
+
978
+ this.setTime(t, true);
979
+ },
980
+
981
+ widgetClick: function(e) {
982
+ e.stopPropagation();
983
+ e.preventDefault();
984
+
985
+ var $input = $(e.target),
986
+ action = $input.closest('a').data('action');
987
+
988
+ if (action) {
989
+ this[action]();
990
+ }
991
+ this.update();
992
+
993
+ if ($input.is('input')) {
994
+ $input.get(0).setSelectionRange(0,2);
995
+ }
996
+ },
997
+
998
+ widgetKeydown: function(e) {
999
+ var $input = $(e.target),
1000
+ name = $input.attr('class').replace('bootstrap-timepicker-', '');
1001
+
1002
+ switch (e.keyCode) {
1003
+ case 9: //tab
1004
+ if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
1005
+ return this.hideWidget();
1006
+ }
1007
+ break;
1008
+ case 27: // escape
1009
+ this.hideWidget();
1010
+ break;
1011
+ case 38: // up arrow
1012
+ e.preventDefault();
1013
+ switch (name) {
1014
+ case 'hour':
1015
+ this.incrementHour();
1016
+ break;
1017
+ case 'minute':
1018
+ this.incrementMinute();
1019
+ break;
1020
+ case 'second':
1021
+ this.incrementSecond();
1022
+ break;
1023
+ case 'meridian':
1024
+ this.toggleMeridian();
1025
+ break;
1026
+ }
1027
+ this.setTime(this.getTime());
1028
+ $input.get(0).setSelectionRange(0,2);
1029
+ break;
1030
+ case 40: // down arrow
1031
+ e.preventDefault();
1032
+ switch (name) {
1033
+ case 'hour':
1034
+ this.decrementHour();
1035
+ break;
1036
+ case 'minute':
1037
+ this.decrementMinute();
1038
+ break;
1039
+ case 'second':
1040
+ this.decrementSecond();
1041
+ break;
1042
+ case 'meridian':
1043
+ this.toggleMeridian();
1044
+ break;
1045
+ }
1046
+ this.setTime(this.getTime());
1047
+ $input.get(0).setSelectionRange(0,2);
1048
+ break;
1049
+ }
1050
+ },
1051
+
1052
+ widgetKeyup: function(e) {
1053
+ 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)) {
1054
+ this.updateFromWidgetInputs();
1055
+ }
1056
+ }
1057
+ };
1058
+
1059
+ //TIMEPICKER PLUGIN DEFINITION
1060
+ $.fn.timepicker = function(option) {
1061
+ var args = Array.apply(null, arguments);
1062
+ args.shift();
1063
+ return this.each(function() {
1064
+ var $this = $(this),
1065
+ data = $this.data('timepicker'),
1066
+ options = typeof option === 'object' && option;
1067
+
1068
+ if (!data) {
1069
+ $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data()))));
1070
+ }
1071
+
1072
+ if (typeof option === 'string') {
1073
+ data[option].apply(data, args);
1074
+ }
1075
+ });
1076
+ };
1077
+
1078
+ $.fn.timepicker.defaults = {
1079
+ defaultTime: 'current',
1080
+ disableFocus: false,
1081
+ disableMousewheel: false,
1082
+ isOpen: false,
1083
+ minuteStep: 15,
1084
+ modalBackdrop: false,
1085
+ orientation: { x: 'auto', y: 'auto'},
1086
+ secondStep: 15,
1087
+ showSeconds: false,
1088
+ showInputs: true,
1089
+ showMeridian: true,
1090
+ template: 'dropdown',
1091
+ appendWidgetTo: 'body',
1092
+ showWidgetOnAddonClick: true
1093
+ };
1094
+
1095
+ $.fn.timepicker.Constructor = Timepicker;
1096
+
1097
+ $(document).on(
1098
+ 'focus.timepicker.data-api click.timepicker.data-api',
1099
+ '[data-provide="timepicker"]',
1100
+ function(e){
1101
+ var $this = $(this);
1102
+ if ($this.data('timepicker')) {
1103
+ return;
1104
+ }
1105
+ e.preventDefault();
1106
+ // component click requires us to explicitly show it
1107
+ $this.timepicker();
1108
+ }
1109
+ );
1110
+
1111
+ })(jQuery, window, document);