PageSourceSearch

https://redhardnheavy.com/wp-content/plugins/wp-gcalendar-pro/public/js/jquery.timepicker.js?ver=7.0.6

js redhardnheavy.com collected 2026-10-02 07:47:53 UTC 29,675 bytes, 1,202 lines download raw bytes

1/*!
2 * jquery-timepicker v1.8.9 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
3 * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
4 * License: MIT
5 */
6
7
8(function (factory) {
9    if (typeof exports === "object" && exports &&
10        typeof module === "object" && module && module.exports === exports) {
11        // Browserify. Attach to jQuery module.
12        factory(require("jquery"));
13    } else if (typeof define === 'function' && define.amd) {
14		// AMD. Register as an anonymous module.
15		define(['jquery'], factory);
16	} else {
17		// Browser globals
18		factory(jQuery);
19	}
20}(function ($) {
21	var _baseDate = _generateBaseDate();
22	var _ONE_DAY = 86400;
23	var _lang = {
24		am: 'am',
25		pm: 'pm',
26		AM: 'AM',
27		PM: 'PM',
28		decimal: '.',
29		mins: 'mins',
30		hr: 'hr',
31		hrs: 'hrs'
32	};
33
34	var methods = {
35		init: function(options)
36		{
37			return this.each(function()
38			{
39				var self = $(this);
40
41				// pick up settings from data attributes
42				var attributeOptions = [];
43				for (var key in $.fn.timepicker.defaults) {
44					if (self.data(key))  {
45						attributeOptions[key] = self.data(key);
46					}
47				}
48
49				var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
50
51				if (settings.lang) {
52					_lang = $.extend(_lang, settings.lang);
53				}
54
55				settings = _parseSettings(settings);
56				self.data('timepicker-settings', settings);
57				self.addClass('ui-timepicker-input');
58
59				if (settings.useSelect) {
60					_render(self);
61				} else {
62					self.prop('autocomplete', 'off');
63					if (settings.showOn) {
64						for (var i in settings.showOn) {
65							self.on(settings.showOn[i]+'.timepicker', methods.show);
66						}
67					}
68					self.on('change.timepicker', _formatValue);
69					self.on('keydown.timepicker', _keydownhandler);
70					self.on('keyup.timepicker', _keyuphandler);
71					if (settings.disableTextInput) {
72						self.on('keydown.timepicker', function(e) { e.preventDefault(); });
73					}
74
75					_formatValue.call(self.get(0));
76				}
77			});
78		},
79
80		show: function(e)
81		{
82			var self = $(this);
83			var settings = self.data('timepicker-settings');
84
85			if (e) {
86				e.preventDefault();
87			}
88
89			if (settings.useSelect) {
90				self.data('timepicker-list').focus();
91				return;
92			}
93
94			if (_hideKeyboard(self)) {
95				// block the keyboard on mobile devices
96				self.blur();
97			}
98
99			var list = self.data('timepicker-list');
100
101			// check if input is readonly
102			if (self.prop('readonly')) {
103				return;
104			}
105
106			// check if list needs to be rendered
107			if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
108				_render(self);
109				list = self.data('timepicker-list');
110			}
111
112			if (_isVisible(list)) {
113				return;
114			}
115
116			self.data('ui-timepicker-value', self.val());
117			_setSelected(self, list);
118
119			// make sure other pickers are hidden
120			methods.hide();
121
122			// position the dropdown relative to the input
123			list.show();
124			var listOffset = {};
125
126			if (settings.orientation.match(/r/)) {
127				// right-align the dropdown
128				listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
129			} else {
130				// left-align the dropdown
131				listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
132			}
133
134			var verticalOrientation;
135			if (settings.orientation.match(/t/)) {
136				verticalOrientation = 't';
137			} else if (settings.orientation.match(/b/)) {
138				verticalOrientation = 'b';
139			} else if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
140				verticalOrientation = 't';
141			} else {
142				verticalOrientation = 'b';
143			}
144
145			if (verticalOrientation == 't') {
146				// position the dropdown on top
147				list.addClass('ui-timepicker-positioned-top');
148				listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
149			} else {
150				// put it under the input
151				list.removeClass('ui-timepicker-positioned-top');
152				listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
153			}
154
155			list.offset(listOffset);
156
157			// position scrolling
158			var selected = list.find('.ui-timepicker-selected');
159
160			if (!selected.length) {
161				var timeInt = _time2int(_getTimeValue(self));
162				if (timeInt !== null) {
163					selected = _findRow(self, list, timeInt);
164				} else if (settings.scrollDefault) {
165					selected = _findRow(self, list, settings.scrollDefault());
166				}
167			}
168
169			if (selected && selected.length) {
170				var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
171				list.scrollTop(topOffset);
172			} else {
173				list.scrollTop(0);
174			}
175
176			// prevent scroll propagation
177			if(settings.stopScrollPropagation) {
178				$(document).on('wheel.ui-timepicker', '.ui-timepicker-wrapper', function(e){
179					e.preventDefault();
180					var currentScroll = $(this).scrollTop();
181					$(this).scrollTop(currentScroll + e.originalEvent.deltaY);
182				});
183			}
184
185			// attach close handlers
186			$(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
187			$(window).on('resize.ui-timepicker', _closeHandler);
188			if (settings.closeOnWindowScroll) {
189				$(document).on('scroll.ui-timepicker', _closeHandler);
190			}
191
192			self.trigger('showTimepicker');
193
194			return this;
195		},
196
197		hide: function(e)
198		{
199			var self = $(this);
200			var settings = self.data('timepicker-settings');
201
202			if (settings && settings.useSelect) {
203				self.blur();
204			}
205
206			$('.ui-timepicker-wrapper').each(function() {
207				var list = $(this);
208				if (!_isVisible(list)) {
209					return;
210				}
211
212				var self = list.data('timepicker-input');
213				var settings = self.data('timepicker-settings');
214
215				if (settings && settings.selectOnBlur) {
216					_selectValue(self);
217				}
218
219				list.hide();
220				self.trigger('hideTimepicker');
221			});
222
223			return this;
224		},
225
226		option: function(key, value)
227		{
228			return this.each(function(){
229				var self = $(this);
230				var settings = self.data('timepicker-settings');
231				var list = self.data('timepicker-list');
232
233				if (typeof key == 'object') {
234					settings = $.extend(settings, key);
235
236				} else if (typeof key == 'string' && typeof value != 'undefined') {
237					settings[key] = value;
238
239				} else if (typeof key == 'string') {
240					return settings[key];
241				}
242
243				settings = _parseSettings(settings);
244
245				self.data('timepicker-settings', settings);
246
247				if (list) {
248					list.remove();
249					self.data('timepicker-list', false);
250				}
251
252				if (settings.useSelect) {
253					_render(self);
254				}
255			});
256		},
257
258		getSecondsFromMidnight: function()
259		{
260			return _time2int(_getTimeValue(this));
261		},
262
263		getTime: function(relative_date)
264		{
265			var self = this;
266
267			var time_string = _getTimeValue(self);
268			if (!time_string) {
269				return null;
270			}
271
272			var offset = _time2int(time_string);
273			if (offset === null) {
274				return null;
275			}
276
277			if (!relative_date) {
278				relative_date = _baseDate;
279			}
280
281			// construct a Date from relative date, and offset's time
282			var time = new Date(relative_date);
283			time.setHours(offset / 3600);
284			time.setMinutes(offset % 3600 / 60);
285			time.setSeconds(offset % 60);
286			time.setMilliseconds(0);
287
288			return time;
289		},
290
291		setTime: function(value)
292		{
293			var self = this;
294			var settings = self.data('timepicker-settings');
295
296			if (settings.forceRoundTime) {
297				var prettyTime = _roundAndFormatTime(_time2int(value), settings)
298			} else {
299				var prettyTime = _int2time(_time2int(value), settings);
300			}
301
302			if (value && prettyTime === null && settings.noneOption) {
303				prettyTime = value;
304			}
305
306			_setTimeValue(self, prettyTime);
307			if (self.data('timepicker-list')) {
308				_setSelected(self, self.data('timepicker-list'));
309			}
310
311			return this;
312		},
313
314		remove: function()
315		{
316			var self = this;
317
318			// check if this element is a timepicker
319			if (!self.hasClass('ui-timepicker-input')) {
320				return;
321			}
322
323			var settings = self.data('timepicker-settings');
324			self.removeAttr('autocomplete', 'off');
325			self.removeClass('ui-timepicker-input');
326			self.removeData('timepicker-settings');
327			self.off('.timepicker');
328
329			// timepicker-list won't be present unless the user has interacted with this timepicker
330			if (self.data('timepicker-list')) {
331				self.data('timepicker-list').remove();
332			}
333
334			if (settings.useSelect) {
335				self.show();
336			}
337
338			self.removeData('timepicker-list');
339
340			return this;
341		}
342	};
343
344	// private methods
345
346	function _isVisible(elem)
347	{
348		var el = elem[0];
349		return el.offsetWidth > 0 && el.offsetHeight > 0;
350	}
351
352	function _parseSettings(settings)
353	{
354		if (settings.minTime) {
355			settings.minTime = _time2int(settings.minTime);
356		}
357
358		if (settings.maxTime) {
359			settings.maxTime = _time2int(settings.maxTime);
360		}
361
362		if (settings.durationTime && typeof settings.durationTime !== 'function') {
363			settings.durationTime = _time2int(settings.durationTime);
364		}
365
366		if (settings.scrollDefault == 'now') {
367			settings.scrollDefault = function() {
368				return settings.roundingFunction(_time2int(new Date()), settings);
369			}
370		} else if (settings.scrollDefault && typeof settings.scrollDefault != 'function') {
371			var val = settings.scrollDefault;
372			settings.scrollDefault = function() {
373				return settings.roundingFunction(_time2int(val), settings);
374			}
375		} else if (settings.minTime) {
376			settings.scrollDefault = function() {
377				return settings.roundingFunction(settings.minTime, settings);
378			}
379		}
380
381		if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
382			settings._twelveHourTime = true;
383		}
384
385		if (settings.showOnFocus === false && settings.showOn.indexOf('focus') != -1) {
386			settings.showOn.splice(settings.showOn.indexOf('focus'), 1);
387		}
388
389		if (settings.disableTimeRanges.length > 0) {
390			// convert string times to integers
391			for (var i in settings.disableTimeRanges) {
392				settings.disableTimeRanges[i] = [
393					_time2int(settings.disableTimeRanges[i][0]),
394					_time2int(settings.disableTimeRanges[i][1])
395				];
396			}
397
398			// sort by starting time
399			settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
400				return a[0] - b[0];
401			});
402
403			// merge any overlapping ranges
404			for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
405				if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
406					settings.disableTimeRanges[i-1] = [
407						Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
408						Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
409					];
410					settings.disableTimeRanges.splice(i, 1);
411				}
412			}
413		}
414
415		return settings;
416	}
417
418	function _render(self)
419	{
420		var settings = self.data('timepicker-settings');
421		var list = self.data('timepicker-list');
422
423		if (list && list.length) {
424			list.remove();
425			self.data('timepicker-list', false);
426		}
427
428		if (settings.useSelect) {
429			list = $('<select />', { 'class': 'ui-timepicker-select' });
430			var wrapped_list = list;
431		} else {
432			list = $('<ul />', { 'class': 'ui-timepicker-list' });
433
434			var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
435			wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
436		}
437
438		if (settings.noneOption) {
439			if (settings.noneOption === true) {
440				settings.noneOption = (settings.useSelect) ? 'Time...' : 'None';
441			}
442
443			if ($.isArray(settings.noneOption)) {
444				for (var i in settings.noneOption) {
445					if (parseInt(i, 10) == i){
446						var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
447						list.append(noneElement);
448					}
449				}
450			} else {
451				var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect);
452				list.append(noneElement);
453			}
454		}
455
456		if (settings.className) {
457			wrapped_list.addClass(settings.className);
458		}
459
460		if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
461			var stepval = typeof settings.step == 'function' ? 'function' : settings.step;
462			wrapped_list.addClass('ui-timepicker-with-duration');
463			wrapped_list.addClass('ui-timepicker-step-'+settings.step);
464		}
465
466		var durStart = settings.minTime;
467		if (typeof settings.durationTime === 'function') {
468			durStart = _time2int(settings.durationTime());
469		} else if (settings.durationTime !== null) {
470			durStart = settings.durationTime;
471		}
472		var start = (settings.minTime !== null) ? settings.minTime : 0;
473		var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
474
475		if (end < start) {
476			// make sure the end time is greater than start time, otherwise there will be no list to show
477			end += _ONE_DAY;
478		}
479
480		if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.show2400) {
481			// show a 24:00 option when using military time
482			end = _ONE_DAY;
483		}
484
485		var dr = settings.disableTimeRanges;
486		var drCur = 0;
487		var drLen = dr.length;
488
489		var stepFunc = settings.step;
490		if (typeof stepFunc != 'function') {
491			stepFunc = function() {
492				return settings.step;
493			}
494		}
495
496		for (var i=start, j=0; i <= end; j++, i += stepFunc(j)*60) {
497			var timeInt = i;
498			var timeString = _int2time(timeInt, settings);
499
500			if (settings.useSelect) {
501				var row = $('<option />', { 'value': timeString });
502				row.text(timeString);
503			} else {
504				var row = $('<li />');
505				row.addClass(timeInt % 86400 < 43200 ? 'ui-timepicker-am' : 'ui-timepicker-pm');
506				row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
507				row.text(timeString);
508			}
509
510			if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
511				var durationString = _int2duration(i - durStart, settings.step);
512				if (settings.useSelect) {
513					row.text(row.text()+' ('+durationString+')');
514				} else {
515					var duration = $('<span />', { 'class': 'ui-timepicker-duration' });
516					duration.text(' ('+durationString+')');
517					row.append(duration);
518				}
519			}
520
521			if (drCur < drLen) {
522				if (timeInt >= dr[drCur][1]) {
523					drCur += 1;
524				}
525
526				if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
527					if (settings.useSelect) {
528						row.prop('disabled', true);
529					} else {
530						row.addClass('ui-timepicker-disabled');
531					}
532				}
533			}
534
535			list.append(row);
536		}
537
538		wrapped_list.data('timepicker-input', self);
539		self.data('timepicker-list', wrapped_list);
540
541		if (settings.useSelect) {
542			if (self.val()) {
543				list.val(_roundAndFormatTime(_time2int(self.val()), settings));
544			}
545
546			list.on('focus', function(){
547				$(this).data('timepicker-input').trigger('showTimepicker');
548			});
549			list.on('blur', function(){
550				$(this).data('timepicker-input').trigger('hideTimepicker');
551			});
552			list.on('change', function(){
553				_setTimeValue(self, $(this).val(), 'select');
554			});
555
556			_setTimeValue(self, list.val(), 'initial');
557			self.hide().after(list);
558		} else {
559			var appendTo = settings.appendTo;
560			if (typeof appendTo === 'string') {
561				appendTo = $(appendTo);
562			} else if (typeof appendTo === 'function') {
563				appendTo = appendTo(self);
564			}
565			appendTo.append(wrapped_list);
566			_setSelected(self, list);
567
568			list.on('mousedown', 'li', function(e) {
569
570				// hack: temporarily disable the focus handler
571				// to deal with the fact that IE fires 'focus'
572				// events asynchronously
573				self.off('focus.timepicker');
574				self.on('focus.timepicker-ie-hack', function(){
575					self.off('focus.timepicker-ie-hack');
576					self.on('focus.timepicker', methods.show);
577				});
578
579				if (!_hideKeyboard(self)) {
580					self[0].focus();
581				}
582
583				// make sure only the clicked row is selected
584				list.find('li').removeClass('ui-timepicker-selected');
585				$(this).addClass('ui-timepicker-selected');
586
587				if (_selectValue(self)) {
588					self.trigger('hideTimepicker');
589
590					list.on('mouseup.timepicker', 'li', function(e) {
591						list.off('mouseup.timepicker');
592						wrapped_list.hide();
593					});
594				}
595			});
596		}
597	}
598
599	function _generateNoneElement(optionValue, useSelect)
600	{
601		var label, className, value;
602
603		if (typeof optionValue == 'object') {
604			label = optionValue.label;
605			className = optionValue.className;
606			value = optionValue.value;
607		} else if (typeof optionValue == 'string') {
608			label = optionValue;
609		} else {
610			$.error('Invalid noneOption value');
611		}
612
613		if (useSelect) {
614			return $('<option />', {
615					'value': value,
616					'class': className,
617					'text': label
618				});
619		} else {
620			return $('<li />', {
621					'class': className,
622					'text': label
623				}).data('time', value);
624		}
625	}
626
627	function _roundAndFormatTime(seconds, settings)
628	{
629		seconds = settings.roundingFunction(seconds, settings);
630		if (seconds !== null) {
631			return _int2time(seconds, settings);
632		}
633	}
634
635	function _generateBaseDate()
636	{
637		return new Date(1970, 0, 1, 0, 0, 0);
638	}
639
640	// event handler to decide whether to close timepicker
641	function _closeHandler(e)
642	{
643		var target = $(e.target);
644		var input = target.closest('.ui-timepicker-input');
645		if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
646			methods.hide();
647			$(document).unbind('.ui-timepicker');
648			$(window).unbind('.ui-timepicker');
649		}
650	}
651
652	function _hideKeyboard(self)
653	{
654		var settings = self.data('timepicker-settings');
655		return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
656	}
657
658	function _findRow(self, list, value)
659	{
660		if (!value && value !== 0) {
661			return false;
662		}
663
664		var settings = self.data('timepicker-settings');
665		var out = false;
666		var value = settings.roundingFunction(value, settings);
667
668		// loop through the menu items
669		list.find('li').each(function(i, obj) {
670			var jObj = $(obj);
671			if (typeof jObj.data('time') != 'number') {
672				return;
673			}
674
675			if (jObj.data('time') == value) {
676				out = jObj;
677				return false;
678			}
679		});
680
681		return out;
682	}
683
684	function _setSelected(self, list)
685	{
686		list.find('li').removeClass('ui-timepicker-selected');
687
688		var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
689		if (timeValue === null) {
690			return;
691		}
692
693		var selected = _findRow(self, list, timeValue);
694		if (selected) {
695
696			var topDelta = selected.offset().top - list.offset().top;
697
698			if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
699				list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
700			}
701
702			selected.addClass('ui-timepicker-selected');
703		}
704	}
705
706
707	function _formatValue(e, origin)
708	{
709		if (this.value === '' || origin == 'timepicker') {
710			return;
711		}
712
713		var self = $(this);
714
715		if (self.is(':focus') && (!e || e.type != 'change')) {
716			return;
717		}
718
719		var settings = self.data('timepicker-settings');
720		var seconds = _time2int(this.value, settings);
721
722		if (seconds === null) {
723			self.trigger('timeFormatError');
724			return;
725		}
726
727		var rangeError = false;
728		// check that the time in within bounds
729		if (settings.minTime !== null && seconds < settings.minTime) {
730			rangeError = true;
731		} else if (settings.maxTime !== null && seconds > settings.maxTime) {
732			rangeError = true;
733		}
734
735		// check that time isn't within disabled time ranges
736		$.each(settings.disableTimeRanges, function(){
737			if (seconds >= this[0] && seconds < this[1]) {
738				rangeError = true;
739				return false;
740			}
741		});
742
743		if (settings.forceRoundTime) {
744			seconds = settings.roundingFunction(seconds, settings);
745		}
746
747		var prettyTime = _int2time(seconds, settings);
748
749		if (rangeError) {
750			if (_setTimeValue(self, prettyTime, 'error')) {
751				self.trigger('timeRangeError');
752			}
753		} else {
754			_setTimeValue(self, prettyTime);
755		}
756	}
757
758	function _getTimeValue(self)
759	{
760		if (self.is('input')) {
761			return self.val();
762		} else {
763			// use the element's data attributes to store values
764			return self.data('ui-timepicker-value');
765		}
766	}
767
768	function _setTimeValue(self, value, source)
769	{
770		if (self.is('input')) {
771			self.val(value);
772
773			var settings = self.data('timepicker-settings');
774			if (settings.useSelect && source != 'select' && source != 'initial') {
775				self.data('timepicker-list').val(_roundAndFormatTime(_time2int(value), settings));
776			}
777		}
778
779		if (self.data('ui-timepicker-value') != value) {
780			self.data('ui-timepicker-value', value);
781			if (source == 'select') {
782				self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker');
783			} else if (source != 'error') {
784				self.trigger('changeTime');
785			}
786
787			return true;
788		} else {
789			self.trigger('selectTime');
790			return false;
791		}
792	}
793
794	/*
795	*  Keyboard navigation via arrow keys
796	*/
797	function _keydownhandler(e)
798	{
799		var self = $(this);
800		var list = self.data('timepicker-list');
801
802		if (!list || !_isVisible(list)) {
803			if (e.keyCode == 40) {
804				// show the list!
805				methods.show.call(self.get(0));
806				list = self.data('timepicker-list');
807				if (!_hideKeyboard(self)) {
808					self.focus();
809				}
810			} else {
811				return true;
812			}
813		}
814
815		switch (e.keyCode) {
816
817			case 13: // return
818				if (_selectValue(self)) {
819					methods.hide.apply(this);
820				}
821
822				e.preventDefault();
823				return false;
824
825			case 38: // up
826				var selected = list.find('.ui-timepicker-selected');
827
828				if (!selected.length) {
829					list.find('li').each(function(i, obj) {
830						if ($(obj).position().top > 0) {
831							selected = $(obj);
832							return false;
833						}
834					});
835					selected.addClass('ui-timepicker-selected');
836
837				} else if (!selected.is(':first-child')) {
838					selected.removeClass('ui-timepicker-selected');
839					selected.prev().addClass('ui-timepicker-selected');
840
841					if (selected.prev().position().top < selected.outerHeight()) {
842						list.scrollTop(list.scrollTop() - selected.outerHeight());
843					}
844				}
845
846				return false;
847
848			case 40: // down
849				selected = list.find('.ui-timepicker-selected');
850
851				if (selected.length === 0) {
852					list.find('li').each(function(i, obj) {
853						if ($(obj).position().top > 0) {
854							selected = $(obj);
855							return false;
856						}
857					});
858
859					selected.addClass('ui-timepicker-selected');
860				} else if (!selected.is(':last-child')) {
861					selected.removeClass('ui-timepicker-selected');
862					selected.next().addClass('ui-timepicker-selected');
863
864					if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
865						list.scrollTop(list.scrollTop() + selected.outerHeight());
866					}
867				}
868
869				return false;
870
871			case 27: // escape
872				list.find('li').removeClass('ui-timepicker-selected');
873				methods.hide();
874				break;
875
876			case 9: //tab
877				methods.hide();
878				break;
879
880			default:
881				return true;
882		}
883	}
884
885	/*
886	*	Time typeahead
887	*/
888	function _keyuphandler(e)
889	{
890		var self = $(this);
891		var list = self.data('timepicker-list');
892		var settings = self.data('timepicker-settings');
893
894		if (!list || !_isVisible(list) || settings.disableTextInput) {
895			return true;
896		}
897
898		switch (e.keyCode) {
899
900			case 96: // numpad numerals
901			case 97:
902			case 98:
903			case 99:
904			case 100:
905			case 101:
906			case 102:
907			case 103:
908			case 104:
909			case 105:
910			case 48: // numerals
911			case 49:
912			case 50:
913			case 51:
914			case 52:
915			case 53:
916			case 54:
917			case 55:
918			case 56:
919			case 57:
920			case 65: // a
921			case 77: // m
922			case 80: // p
923			case 186: // colon
924			case 8: // backspace
925			case 46: // delete
926				if (settings.typeaheadHighlight) {
927					_setSelected(self, list);
928				} else {
929					list.hide();
930				}
931				break;
932		}
933	}
934
935	function _selectValue(self)
936	{
937		var settings = self.data('timepicker-settings');
938		var list = self.data('timepicker-list');
939		var timeValue = null;
940
941		var cursor = list.find('.ui-timepicker-selected');
942
943		if (cursor.hasClass('ui-timepicker-disabled')) {
944			return false;
945		}
946
947		if (cursor.length) {
948			// selected value found
949			timeValue = cursor.data('time');
950		}
951
952		if (timeValue !== null) {
953			if (typeof timeValue != 'string') {
954				timeValue = _int2time(timeValue, settings);
955			}
956
957			_setTimeValue(self, timeValue, 'select');
958		}
959
960		return true;
961	}
962
963	function _int2duration(seconds, step)
964	{
965		seconds = Math.abs(seconds);
966		var minutes = Math.round(seconds/60),
967			duration = [],
968			hours, mins;
969
970		if (minutes < 60) {
971			// Only show (x mins) under 1 hour
972			duration = [minutes, _lang.mins];
973		} else {
974			hours = Math.floor(minutes/60);
975			mins = minutes%60;
976
977			// Show decimal notation (eg: 1.5 hrs) for 30 minute steps
978			if (step == 30 && mins == 30) {
979				hours += _lang.decimal + 5;
980			}
981
982			duration.push(hours);
983			duration.push(hours == 1 ? _lang.hr : _lang.hrs);
984
985			// Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps
986			// and only if there are remainder minutes to show
987			if (step != 30 && mins) {
988				duration.push(mins);
989				duration.push(_lang.mins);
990			}
991		}
992
993		return duration.join(' ');
994	}
995
996	function _int2time(seconds, settings)
997	{
998		if (seconds === null) {
999			return null;
1000		}
1001
1002		var time = new Date(_baseDate.valueOf() + (seconds*1000));
1003
1004		if (isNaN(time.getTime())) {
1005			return null;
1006		}
1007
1008		if ($.type(settings.timeFormat) === "function") {
1009			return settings.timeFormat(time);
1010		}
1011
1012		var output = '';
1013		var hour, code;
1014		for (var i=0; i<settings.timeFormat.length; i++) {
1015
1016			code = settings.timeFormat.charAt(i);
1017			switch (code) {
1018
1019				case 'a':
1020					output += (time.getHours() > 11) ? _lang.pm : _lang.am;
1021					break;
1022
1023				case 'A':
1024					output += (time.getHours() > 11) ? _lang.PM : _lang.AM;
1025					break;
1026
1027				case 'g':
1028					hour = time.getHours() % 12;
1029					output += (hour === 0) ? '12' : hour;
1030					break;
1031
1032				case 'G':
1033					hour = time.getHours();
1034					if (seconds === _ONE_DAY) hour = 24;
1035					output += hour;
1036					break;
1037
1038				case 'h':
1039					hour = time.getHours() % 12;
1040
1041					if (hour !== 0 && hour < 10) {
1042						hour = '0'+hour;
1043					}
1044
1045					output += (hour === 0) ? '12' : hour;
1046					break;
1047
1048				case 'H':
1049					hour = time.getHours();
1050					if (seconds === _ONE_DAY) hour = settings.show2400 ? 24 : 0;
1051					output += (hour > 9) ? hour : '0'+hour;
1052					break;
1053
1054				case 'i':
1055					var minutes = time.getMinutes();
1056					output += (minutes > 9) ? minutes : '0'+minutes;
1057					break;
1058
1059				case 's':
1060					seconds = time.getSeconds();
1061					output += (seconds > 9) ? seconds : '0'+seconds;
1062					break;
1063
1064				case '\\':
1065					// escape character; add the next character and skip ahead
1066					i++;
1067					output += settings.timeFormat.charAt(i);
1068					break;
1069
1070				default:
1071					output += code;
1072			}
1073		}
1074
1075		return output;
1076	}
1077
1078	function _time2int(timeString, settings)
1079	{
1080		if (timeString === '') return null;
1081		if (!timeString || timeString+0 == timeString) return timeString;
1082
1083		if (typeof(timeString) == 'object') {
1084			return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
1085		}
1086
1087		timeString = timeString.toLowerCase().replace(/[\s\.]/g, '');
1088
1089		// if the last character is an "a" or "p", add the "m"
1090		if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
1091			timeString += 'm';
1092		}
1093
1094		var ampmRegex = '(' +
1095			_lang.am.replace('.', '')+'|' +
1096			_lang.pm.replace('.', '')+'|' +
1097			_lang.AM.replace('.', '')+'|' +
1098			_lang.PM.replace('.', '')+')?';
1099
1100		// try to parse time input
1101		var pattern = new RegExp('^'+ampmRegex+'([0-9]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?'+ampmRegex+'$');
1102
1103		var time = timeString.match(pattern);
1104		if (!time) {
1105			return null;
1106		}
1107
1108		var unboundedHour = parseInt(time[2]*1, 10);
1109		var hour = (unboundedHour > 24) ? unboundedHour % 24 : unboundedHour;
1110		var ampm = time[1] || time[5];
1111		var hours = hour;
1112
1113		if (hour <= 12 && ampm) {
1114			var isPm = (ampm == _lang.pm || ampm == _lang.PM);
1115
1116			if (hour == 12) {
1117				hours = isPm ? 12 : 0;
1118			} else {
1119				hours = (hour + (isPm ? 12 : 0));
1120			}
1121		}
1122
1123		var minutes = ( time[3]*1 || 0 );
1124		var seconds = ( time[4]*1 || 0 );
1125		var timeInt = hours*3600 + minutes*60 + seconds;
1126
1127		// if no am/pm provided, intelligently guess based on the scrollDefault
1128		if (hour < 12 && !ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
1129			var delta = timeInt - settings.scrollDefault();
1130			if (delta < 0 && delta >= _ONE_DAY / -2) {
1131				timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
1132			}
1133		}
1134
1135		return timeInt;
1136	}
1137
1138	function _pad2(n) {
1139		return ("0" + n).slice(-2);
1140	}
1141
1142	// Plugin entry
1143	$.fn.timepicker = function(method)
1144	{
1145		if (!this.length) return this;
1146		if (methods[method]) {
1147			// check if this element is a timepicker
1148			if (!this.hasClass('ui-timepicker-input')) {
1149				return this;
1150			}
1151			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
1152		}
1153		else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
1154		else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
1155	};
1156	// Global defaults
1157	$.fn.timepicker.defaults = {
1158		appendTo: 'body',
1159		className: null,
1160		closeOnWindowScroll: false,
1161		disableTextInput: false,
1162		disableTimeRanges: [],
1163		disableTouchKeyboard: false,
1164		durationTime: null,
1165		forceRoundTime: false,
1166		maxTime: null,
1167		minTime: null,
1168		noneOption: false,
1169		orientation: 'l',
1170		roundingFunction: function(seconds, settings) {
1171			if (seconds === null) {
1172				return null;
1173			} else if (typeof settings.step !== "number") {
1174				// TODO: nearest fit irregular steps
1175				return seconds;
1176			} else {
1177				var offset = seconds % (settings.step*60); // step is in minutes
1178
1179				if (offset >= settings.step*30) {
1180					// if offset is larger than a half step, round up
1181					seconds += (settings.step*60) - offset;
1182				} else {
1183					// round down
1184					seconds -= offset;
1185				}
1186
1187				return seconds;
1188			}
1189		},
1190		scrollDefault: null,
1191		selectOnBlur: false,
1192		show2400: false,
1193		showDuration: false,
1194		showOn: ['click', 'focus'],
1195		showOnFocus: true,
1196		step: 30,
1197		stopScrollPropagation: false,
1198		timeFormat: 'g:ia',
1199		typeaheadHighlight: true,
1200		useSelect: false
1201	};
1202}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.