PageSourceSearch

https://www.tlvmarathon.co.il/includes/timepicker/timepicki.js?v=Iam6V7bnAom1KuoagAFRum1vmGOAaSiVhqFjD5X49EY1

js tlvmarathon.co.il collected 2026-10-02 11:26:36 UTC 19,488 bytes, 608 lines download raw bytes

1/* 
2 * Author: @senthil2rajan
3 * plugin: timepicker
4 * website: senthilraj.github.io/Timepicki
5 */
6(function($) {
7
8	$.fn.timepicki = function(options) {
9
10		var defaults = {
11			format_output: function(tim, mini, meri) {
12			    if (settings.show_meridian) {
13                    // limit hours between 1 and 12 - inculsive.
14			        tim = Math.min(Math.max(parseInt(tim), 1), 12);
15			        if (tim < 10)
16			            tim = "0" + tim;
17
18			        
19			        mini = Math.min(Math.max(parseInt(mini), 0), 59);
20			        if (mini < 10)
21			            mini = "0" + mini;
22
23					return tim + ":" + mini + " " + meri;
24			    } else {
25
26			        // limit hours between 0 and 23 - inculsive.
27			        tim = Math.min(Math.max(parseInt(tim), 0), 23);
28
29			        if (tim < 10)
30			            tim = "0" + tim;
31
32
33			        mini = Math.min(Math.max(parseInt(mini), 0), 59);
34			        if (mini < 10)
35			            mini = "0" + mini;
36                    
37					return tim + ":" + mini;
38				}
39			},
40			increase_direction: 'up',
41			custom_classes: '',
42			min_hour_value: 1,
43			max_hour_value: 12,
44			show_meridian: true,
45			step_size_hours: '1',
46			step_size_minutes: '1',
47			overflow_minutes: false,
48			disable_keyboard_mobile: false,
49            max_time: null,
50			reset: false,
51			on_change: null,
52      			input_writable: false
53		};
54
55		var settings = $.extend({}, defaults, options);
56
57		return this.each(function() {
58
59			var ele = $(this);
60			var ele_hei = ele.outerHeight();
61			ele_hei += 10;
62			$(ele).wrap("<div class='time_pick'>");
63			var ele_par = $(this).parents(".time_pick");
64
65			// developer can specify which arrow makes the numbers go up or down
66			var top_arrow_button = (settings.increase_direction === 'down') ?
67				"<div class='prev action-prev'></div>" :
68				"<div class='prev action-next'></div>";
69			var bottom_arrow_button = (settings.increase_direction === 'down') ?
70				"<div class='next action-next'></div>" :
71				"<div class='next action-prev'></div>";
72
73			var new_ele = $(
74				"<div class='timepicker_wrap " + settings.custom_classes + "'>" +
75					"<div class='arrow_top'></div>" +
76					"<div class='time'>" +
77						top_arrow_button +
78						"<div class='ti_tx'><input type='text' class='timepicki-input' title='זמן מטרה שעות' aria-label='זמן מטרה שעות'" + (settings.disable_keyboard_mobile ? "readonly" : "") + "><span class='timepickiHoursTextContainer' style='font:16px OpenSans, sans-serif, arial;'>שעות</span></div>" +
79						bottom_arrow_button +
80					"</div>" +
81					"<div class='mins'>" +
82						top_arrow_button +
83						"<div class='mi_tx'><input type='text' class='timepicki-input' title='זמן מטרה דקות' aria-label='זמן מטרה דקות'" + (settings.disable_keyboard_mobile ? "readonly" : "") + "><span class='timepickiMinutesTextContainer' style='font:16px OpenSans, sans-serif, arial;'>דקות</span></div>" +
84						bottom_arrow_button +
85					"</div>");
86			if(settings.show_meridian){
87				new_ele.append(
88					"<div class='meridian'>" +
89						top_arrow_button +
90						"<div class='mer_tx'><input type='text' class='timepicki-input' readonly></div>" +
91						bottom_arrow_button +
92					"</div>");
93			}
94			if(settings.reset){
95				new_ele.append(
96					"<div><a href='#' class='reset_time'>Reset</a></div>");
97			}
98			ele_par.append(new_ele);
99			var ele_next = $(this).next(".timepicker_wrap");
100			var ele_next_all_child = ele_next.find("div");
101			var inputs = ele_par.find('input');
102			
103			$('.reset_time').on("click", function(event) {
104				ele.val("");
105				close_timepicki();
106			});
107
108			$(".timepicki-input").keydown(function (keyevent) {
109			    // our goal here is very simple.
110			    // no matter what the user presses
111			    // we must ensure that the values in our
112			    // timepicki inputs are valid, and that pressing
113			    // enter does not submit the form if the
114			    // input field on which timepicki is applied is a part of a form.
115			    
116			    
117			    // With that in mind. We proceed like this:
118			    // 1) If enter is pressed:
119			    //      i) Prevent default operations - form submission.
120                //      ii) close_timepicki().
121			    //      iii) return.
122                //
123			    // 2) For any other key presses:
124			    //      i) realize that we cannot check what the user has typed
125			    //         just yet, because this function is a handler
126			    //         that runs before any text is rendered in the input
127			    //         box.
128			    //      ii) So, register a function validate() that will execute right 
129			    //          after the keypress character is rendered. All validation
130                //          is done inside validate().
131                //-----------------------------------------------------------------------------------
132			    //  NOTE:.change() event does not work here, as it is called when input looses focus|
133                //-----------------------------------------------------------------------------------
134
135                // (1)
136			    // prevent potential form submission, if enter is pressed.
137			    if (keyevent.keyCode == 13) {
138
139			        keyevent.preventDefault();
140
141			        set_value();
142			        close_timepicki();
143			        // nothing to do here.
144			        return;
145			    }
146
147
148
149			    // the grand father div specifies the type of 
150			    // input that we are dealing with. if the grandFatherDiv
151			    // has a class "time", then its a time input, if it has a class
152			    // "mins", then its a minutes input, and if it has a class "meri
152dian"
153                // then its a meridian input.
154			    var grandfatherDiv = $(this).parent().parent();
155
156                // aliasing for readability
157			    var input = $(this);
158
159			    // pick the value from the field,
160			    // because before change the field always has a
161                // valid value.
162			    var lastValue = input.val();
163
164                // (2)
165			    // validate() function validates the
166			    // user input. 
167			    function validate() {
168			        
169			        var isValidNumber = /^\d+$/.test(input.val());
170			        var isEmpty = input.val() === "";
171			        
172                    
173			        if (grandfatherDiv.hasClass("time")) { /// HOUR
174
175			            // if its a valid number.
176                        // clip it and assign it.
177			            if (isValidNumber) {
178
179                            // clip number.
180			                var hours = (settings.show_meridian) ?
181                            Math.min(Math.max(parseInt(input.val()), 1), 12) : // for 12 hour date picker.
182			                Math.min(Math.max(parseInt(input.val()), 0), 23); // for 24 hours date picker.
183
184			                isValidNumber = validateMaxTime(input, hours, null);
185
186			                // assign number.
187			                if (isValidNumber)
188			                    input.val(hours);
189			                else
190			                    input.val(lastValue);
191
192			            } else if(!isEmpty) {
193                            // else if the number is invalid and not empty
194                            // assign the lastValue
195			                input.val(lastValue);
196
197			            }
198
199
200
201			        } else if (grandfatherDiv.hasClass("mins")) { /// MINUTE
202
203
204			            // if its a valid number.
205			            // clip it and assign it.
206			            if (isValidNumber) {
207
208			                // clip number.
209			                var minutes = Math.min(Math.max(parseInt(input.val()), 0), 59);
210
211			                isValidNumber = validateMaxTime(input, null, minutes);
212
213			                // assign number.
214			                if (isValidNumber)
215			                    input.val(minutes);
216			                else
217			                    input.val(lastValue);
218
219			            } else if (!isEmpty) {
220			                // else if the number is invalid and not empty
221			                // assign the lastValue
222			                input.val(lastValue);
223
224			            }
225
226
227			        } else if (grandfatherDiv.hasClass("meridian")) { /// MERIDIAN
228			            // key presses should not affect
229			            // meridian - except up and down
230			            // which are handled else where
231                        // and will still work.
232			            keyevent.preventDefault();
233			        } else {
234                        // alert("This should not happen.");
235			        }
236
237			    }
238			    
239			    // wrapValidate() ensures that validate()
240			    // is not called more than once. 'done'
241                // is a flag used to ensure this.
242			    done = false;
243			    function wrapValidate() {
244			        if (!done) {
245
246
247                        validate();
248
249			            done = true;
250                    }
251			    }
252			    // enqueue wrapValidate function before any thing
253			    // else takes place. For this we use setTimeout()
254                // with 0
255			    setTimeout(wrapValidate, 0);
256
257
258
259
260					
261
262			});
263
264			function validateMaxTime(sender, hours, mins) {
265			    isValid = true;
266
267			    if (settings.max_time == null)
268			        return isValid;
269
270			    var context = sender.closest(".timepicker_wrap");
271			    
272			    if (hours == null)
273			        hours = Number($(".time .timepicki-input", context).val());
274			    if (mins == null)
275			        mins = Number($(".mins .timepicki-input", context).val());
276
277			    if (hours > settings.max_time[0] ||
278                    (hours == settings.max_time[0] && mins > settings.max_time[1])) {
279			        isValid = false;
280			    }
281			    
282			    return isValid;
283			}
284
285			// open or close time picker when clicking
286			$(document).on("click", function(event) {
287				if (!$(event.target).is(ele_next) && ele_next.css("display")=="block" && !$(event.target).is($('.reset_time'))) {
288					if (!$(event.target).is(ele)) {
289						set_value(event, !is_element_in_timepicki($(event.target)));
290					} else {
291						var ele_lef =  0;
292						
293						ele_next.css({
294							"top": ele_hei + "px",
295							"left": ele_lef + "px"
296						});
297						open_timepicki();
298					}
299				}
300			});
301
302			// open the modal when the user focuses on the input
303			ele.on('focus', open_timepicki);
304
305			// select all text in input when user focuses on it
306			inputs.on('focus', function() {
307				var input = $(this);
308				if (!input.is(ele)) {
309					input.select();
310				}
311			});
312
313			// allow user to increase and decrease numbers using arrow keys
314			inputs.on('keydown', function(e) {
315				var direction, input = $(this);
316
317				// UP
318				if (e.which === 38) {
319					if (settings.increase_direction === 'down') {
320						direction = 'prev';
321					} else {
322						direction = 'next';
323					}
324				// DOWN
325				} else if (e.which === 40) {
326					if (settings.increase_direction === 'down') {
327						direction = 'next';
328					} else {
329						direction = 'prev';
330					}
331				}
332
333				if (input.closest('.timepicker_wrap .time').length) {
334					change_time(null, direction);
335				} else if (input.closest('.timepicker_wrap .mins').length) {
336					change_mins(null, direction);
337				} else if (input.closest('.timepicker_wrap .meridian').length && settings.show_meridian) {
338					change_meri(null, direction);
339				}
340			});
341
342			// close the modal when the time picker loses keyboard focus
343			inputs.on('blur', function() {
344				setTimeout(function() {
345					var focused_element = $(document.activeElement);
346					if (focused_element.is(':input') && !is_element_in_timepicki(focused_element)) {
347						set_value();
348						close_timepicki();
349					}
350				}, 0);
351			});
352
353			function is_element_in_timepicki(jquery_element) {
354				return $.contains(ele_par[0], jquery_element[0]) || ele_par.is(jquery_element);
355			}
356
357			function set_value(event, close) {
358				// use input values to set the time
359				var tim = ele_next.find(".ti_tx input").val();
360				var mini = ele_next.find(".mi_tx input").val();
361				var meri = "";
362				if(settings.show_meridian){
363					meri = ele_next.find(".mer_tx input").val();
364				}
365				
366				if (tim.length !== 0 && mini.length !== 0 && (!settings.show_meridian || meri.length !== 0)) {
367					// store the value so we can set the initial value
368					// next time the picker is opened
369					ele.attr('data-timepicki-tim', tim);
370					ele.attr('data-timepicki-mini', mini);
371					
372					if(settings.show_meridian){
373						ele.attr('data-timepicki-meri', meri);
374						// set the formatted value
375						ele.val(settings.format_output(tim, mini, meri));
376					}else{
377						ele.val(settings.format_output(tim, mini));
378					}
379				}
380
381				//Call user on_change callback function if set
382				if (settings.on_change !== null) {
383					settings.on_change(ele[0]);
384				}
385
386				if (close) {
387					close_timepicki();
388				}
389			}
390
391			function open_timepicki() {
392				set_date(settings.start_time);
393				ele_next.fadeIn();
394				if(!settings.input_writable) {
395					// focus on the first input and select its contents
396					var first_input = ele_next.find('input:visible').first();
397					first_input.focus();
398				}
399				// if the user presses shift+tab while on the first input,
400				// they mean to exit the time picker and go to the previous field
401				var first_input_exit_handler = function(e) {
402					if (e.which === 9 && e.shiftKey) {
403						first_input.off('keydown', first_input_exit_handler);
404						var all_form_elements = $(':input:visible:not(.timepicki-input)');
405						var index_of_timepicki_input = all_form_elements.index(ele);
406						var previous_form_element = all_form_elements.get(index_of_timepicki_input-1);
407						previous_form_element.focus();
408					}
409				};
410				first_input.on('keydown', first_input_exit_handler);
411			}
412
413			function close_timepicki() {
414				ele_next.fadeOut();
415			}
416
417			function set_date(start_time) {
418				var d, ti, mi, mer;
419
420				// if a value was already picked we will remember that value
421				if (ele.is('[data-timepicki-tim]')) {
422					ti = Number(ele.attr('data-timepicki-tim'));
423					mi = Number(ele.attr('data-timepicki-mini'));
424					if(settings.show_meridian){
425						mer = ele.attr('data-timepicki-meri');
426					}
427				// developer can specify a custom starting value
428				} else if (typeof start_time === 'object') {
429					ti = Number(start_time[0]);
430					mi = Number(start_time[1]);
431					if(settings.show_meridian){
432						mer = start_time[2];
433					}
434				// default is we will use the current time
435				} else {
436					d = new Date();
437					ti = d.getHours();
438					mi = d.getMinutes();
439					mer = "AM";
440					if (settings.show_meridian){
441						if (ti == 0) { // midnight 
442							ti = 12;
443						} else if (ti == 12) { // noon
444							mer = "PM";
445						} else if (ti > 12) {
446							ti -= 12;
447							mer = "PM";
448						}
449					}
450				}
451
452				if (ti < 10) {
453					ele_next.find(".ti_tx input").val("0" + ti);
454				} else {
455					ele_next.find(".ti_tx input").val(ti);
456				}
457				if (mi < 10) {
458					ele_next.find(".mi_tx input").val("0" + mi);
459				} else {
460					ele_next.find(".mi_tx input").val(mi);
461				}
462				if(settings.show_meridian){
463					if (mer < 10) {
464						ele_next.find(".mer_tx input").val("0" + mer);
465					} else {
466						ele_next.find(".mer_tx input").val(mer);
467					}
468				}
469			}
470
471			function change_time(cur_ele, direction) {
472				var cur_cli = "time";
473				var cur_time = Number(ele_next.find("." + cur_cli + " .ti_tx input").val());
474				var ele_st = Number(settings.min_hour_value);
475				var ele_en = Number(settings.max_hour_value);
476				var step_size = Number(settings.step_size_hours);
477				if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') {
478				    if (validateMaxTime(ele_next, cur_time + step_size, null) == false)
479				        return;
480
481				    if (cur_time + step_size > ele_en) {
482						var min_value = ele_st;
483						if (min_value < 10) {
484							min_value = '0' + min_value;
485						} else {
486							min_value = String(min_value);
487						}
488						ele_next.find("." + cur_cli + " .ti_tx input").val(min_value);
489					} else {
490						cur_time = cur_time + step_size;
491						if (cur_time < 10) {
492							cur_time = "0" + cur_time;
493						}
494						ele_next.find("." + cur_cli + " .ti_tx input").val(cur_time);
495					}
496				} else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') {
497				    if (validateMaxTime(ele_next, cur_time - step_size, null) == false)
498				        return;
499
500					var minValue = Number(settings.min_hour_value)
501					if (cur_time - step_size < minValue) {
502					    var max_value = ele_en;
503					    if (validateMaxTime(ele_next, max_value, null) == false)
504					        return;
505
506						if (max_value < 10) {
507							max_value = '0' + max_value;
508						} else {
509							max_value = String(max_value);
510						}
511						ele_next.find("." + cur_cli + " .ti_tx input").val(max_value);
512					} else {
513						cur_time = cur_time - step_size;
514						if (cur_time < 10) {
515							cur_time = "0" + cur_time;
516						}
517						ele_next.find("." + cur_cli + " .ti_tx input").val(cur_time);
518					}
519				}
520			}
521
522			function change_mins(cur_ele, direction) {
523				var cur_cli = "mins";
524				var cur_mins = Number(ele_next.find("." + cur_cli + " .mi_tx input").val());
525				var ele_st = 0;
526				var ele_en = 59;
527				var step_size = Number(settings.step_size_minutes);
528				if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') {
529				    if (validateMaxTime(ele_next, null, cur_mins + step_size) == false)
530				        return;
531
532					if (cur_mins + step_size > ele_en) {
533						ele_next.find("." + cur_cli + " .mi_tx input").val("00");
534						if(settings.overflow_minutes){
535							change_time(null, 'next');
536						}
537					} else {
538						cur_mins = cur_mins + step_size;
539						if (cur_mins < 10) {
540							ele_next.find("." + cur_cli + " .mi_tx input").val("0" + cur_mins);
541						} else {
542							ele_next.find("." + cur_cli + " .mi_tx input").val(cur_mins);
543						}
544					}
545				} else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') {
546				    if (validateMaxTime(ele_next, null, cur_mins - step_size) == false)
547				        return;
548
549				    if (cur_mins - step_size <= -1) {
550				        if (validateMaxTime(ele_next, null, ele_en + 1 - step_size) == false)
551				            return;
552
553						ele_next.find("." + cur_cli + " .mi_tx input").val(ele_en + 1 - step_size);
554						if(settings.overflow_minutes){
555							change_time(null, 'prev');
556						}
557					} else {
558						cur_mins = cur_mins - step_size;
559						if (cur_mins < 10) {
560							ele_next.find("." + cur_cli + " .mi_tx input").val("0" + cur_mins);
561						} else {
562							ele_next.find("." + cur_cli + " .mi_tx input").val(cur_mins);
563						}
564					}
565				}
566			}
567
568			function change_meri(cur_ele, direction) {
569				var cur_cli = "meridian";
570				var ele_st = 0;
571				var ele_en = 1;
572				var cur_mer = null;
573				cur_mer = ele_next.find("." + cur_cli + " .mer_tx input").val();
574				if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') {
575					if (cur_mer == "AM") {
576						ele_next.find("." + cur_cli + " .mer_tx input").val("PM");
577					} else {
578						ele_next.find("." + cur_cli + " .mer_tx input").val("AM");
579					}
580				} else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') {
581					if (cur_mer == "AM") {
582						ele_next.find("." + cur_cli + " .mer_tx input").val("PM");
583					} else {
584						ele_next.find("." + cur_cli + " .mer_tx input").val("AM");
585					}
586				}
587			}
588
589			// handle clicking on the arrow icons
590			var cur_next = ele_next.find(".action-next");
591			var cur_prev = ele_next.find(".action-prev");
592			$(cur_prev).add(cur_next).on("click", function() {
593				var cur_ele = $(this);
594				if (cur_ele.parent().attr("class") == "time") {
595					change_time(cur_ele);
596				} else if (cur_ele.parent().attr("class") == "mins") {
597					change_mins(cur_ele);
598				} else {
599					if(settings.show_meridian){
600						change_meri(cur_ele);
601					}
602				}
603			});
604
605		});
606	};
607
608}(jQuery));

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.