/* * Author: @senthil2rajan * plugin: timepicker * website: senthilraj.github.io/Timepicki */ (function($) { $.fn.timepicki = function(options) { var defaults = { format_output: function(tim, mini, meri) { if(settings.show_meridian){ return tim + " : " + mini + " : " + meri; }else{ return tim + " : " + mini; } }, increase_direction: 'down', custom_classes: '', min_hour_value: 1, max_hour_value: 12, show_meridian: true, step_size_hours: '1', step_size_minutes: '1', overflow_minutes: false, disable_keyboard_mobile: false, reset: false, on_change: null }; var settings = $.extend({}, defaults, options); return this.each(function() { var ele = $(this); var ele_hei = ele.outerHeight(); ele_hei += 10; $(ele).wrap("
"); var ele_par = $(this).parents(".time_pick"); // developer can specify which arrow makes the numbers go up or down var top_arrow_button = (settings.increase_direction === 'down') ? "" : ""; var bottom_arrow_button = (settings.increase_direction === 'down') ? "" : ""; var new_ele = $( "
" + "
" + "
" + top_arrow_button + "
" + bottom_arrow_button + "
" + "
" + top_arrow_button + "
" + bottom_arrow_button + "
"); if(settings.show_meridian){ new_ele.append( "
" + top_arrow_button + "
" + bottom_arrow_button + "
"); } if(settings.reset){ new_ele.append( "
Reset
"); } ele_par.append(new_ele); var ele_next = $(this).next(".timepicker_wrap"); var ele_next_all_child = ele_next.find("div"); var inputs = ele_par.find('input'); $('.reset_time').on("click", function(event) { ele.val(""); close_timepicki(); }); $(".timepicki-input").keydown( function(keyevent){ var len = $(this).val().length; // Allow: backspace, delete, tab, escape, enter and . if ($.inArray(keyevent.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 || // Allow: Ctrl+A (keyevent.keyCode == 65 && keyevent.ctrlKey === true) || // Allow: home, end, left, right (keyevent.keyCode >= 35 && keyevent.keyCode <= 39)) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((keyevent.shiftKey || (keyevent.keyCode < 48 || keyevent.keyCode > 57)) && (keyevent.keyCode < 96 || keyevent.keyCode > 105) || len==2 ) { keyevent.preventDefault(); } }); // open or close time picker when clicking $(document).on("click", function(event) { if (!$(event.target).is(ele_next) && ele_next.css("display")=="block" && !$(event.target).is($('.reset_time'))) { if (!$(event.target).is(ele)) { set_value(event, !is_element_in_timepicki($(event.target))); } else { var ele_lef = 0; ele_next.css({ "top": ele_hei + "px", "left": ele_lef + "px" }); open_timepicki(); } } }); // open the modal when the user focuses on the input ele.on('focus', open_timepicki); // select all text in input when user focuses on it inputs.on('focus', function() { var input = $(this); if (!input.is(ele)) { input.select(); } }); // allow user to increase and decrease numbers using arrow keys inputs.on('keydown', function(e) { var direction, input = $(this); // UP if (e.which === 38) { if (settings.increase_direction === 'down') { direction = 'prev'; } else { direction = 'next'; } // DOWN } else if (e.which === 40) { if (settings.increase_direction === 'down') { direction = 'next'; } else { direction = 'prev'; } } if (input.closest('.timepicker_wrap .time').length) { change_time(null, direction); } else if (input.closest('.timepicker_wrap .mins').length) { change_mins(null, direction); } else if (input.closest('.timepicker_wrap .meridian').length && settings.show_meridian) { change_meri(null, direction); } }); // close the modal when the time picker loses keyboard focus inputs.on('blur', function() { setTimeout(function() { var focused_element = $(document.activeElement); if (focused_element.is(':input') && !is_element_in_timepicki(focused_element)) { set_value(); close_timepicki(); } }, 0); }); function is_element_in_timepicki(jquery_element) { return $.contains(ele_par[0], jquery_element[0]) || ele_par.is(jquery_element); } function set_value(event, close) { // use input values to set the time var tim = ele_next.find(".ti_tx input").val(); var mini = ele_next.find(".mi_tx input").val(); var meri = ""; if(settings.show_meridian){ meri = ele_next.find(".mer_tx input").val(); } if (tim.length !== 0 && mini.length !== 0 && (!settings.show_meridian || meri.length !== 0)) { // store the value so we can set the initial value // next time the picker is opened ele.attr('data-timepicki-tim', tim); ele.attr('data-timepicki-mini', mini); if(settings.show_meridian){ ele.attr('data-timepicki-meri', meri); // set the formatted value ele.val(settings.format_output(tim, mini, meri)); }else{ ele.val(settings.format_output(tim, mini)); } } //Call user on_change callback function if set if (settings.on_change !== null) { settings.on_change(ele[0]); } if (close) { close_timepicki(); } } function open_timepicki() { set_date(settings.start_time); ele_next.fadeIn(); // focus on the first input and select its contents var first_input = ele_next.find('input:visible').first(); first_input.focus(); // if the user presses shift+tab while on the first input, // they mean to exit the time picker and go to the previous field var first_input_exit_handler = function(e) { if (e.which === 9 && e.shiftKey) { first_input.off('keydown', first_input_exit_handler); var all_form_elements = $(':input:visible:not(.timepicki-input)'); var index_of_timepicki_input = all_form_elements.index(ele); var previous_form_element = all_form_elements.get(index_of_timepicki_input-1); previous_form_element.focus(); } }; first_input.on('keydown', first_input_exit_handler); } function close_timepicki() { ele_next.fadeOut(); } function set_date(start_time) { var d, ti, mi, mer; // if a value was already picked we will remember that value if (ele.is('[data-timepicki-tim]')) { ti = Number(ele.attr('data-timepicki-tim')); mi = Number(ele.attr('data-timepicki-mini')); if(settings.show_meridian){ mer = ele.attr('data-timepicki-meri'); } // developer can specify a custom starting value } else if (typeof start_time === 'object') { ti = Number(start_time[0]); mi = Number(start_time[1]); if(settings.show_meridian){ mer = start_time[2]; } // default is we will use the current time } else { d = new Date(); ti = d.getHours(); mi = d.getMinutes(); mer = "AM"; if (12 < ti && settings.show_meridian) { ti -= 12; mer = "PM"; } } if (ti < 10) { ele_next.find(".ti_tx input").val("0" + ti); } else { ele_next.find(".ti_tx input").val(ti); } if (mi < 10) { ele_next.find(".mi_tx input").val("0" + mi); } else { ele_next.find(".mi_tx input").val(mi); } if(settings.show_meridian){ if (mer < 10) { ele_next.find(".mer_tx input").val("0" + mer); } else { ele_next.find(".mer_tx input").val(mer); } } } function change_time(cur_ele, direction) { var cur_cli = "time"; var cur_time = Number(ele_next.find("." + cur_cli + " .ti_tx input").val()); var ele_st = Number(settings.min_hour_value); var ele_en = Number(settings.max_hour_value); var step_size = Number(settings.step_size_hours); if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') { if (cur_time + step_size > ele_en) { var min_value = ele_st; if (min_value < 10) { min_value = '0' + min_value; } else { min_value = String(min_value); } ele_next.find("." + cur_cli + " .ti_tx input").val(min_value); } else { cur_time = cur_time + step_size; if (cur_time < 10) { cur_time = "0" + cur_time; } ele_next.find("." + cur_cli + " .ti_tx input").val(cur_time); } } else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') { var minValue = Number(settings.min_hour_value) if (cur_time - step_size < minValue) { var max_value = ele_en; if (max_value < 10) { max_value = '0' + max_value; } else { max_value = String(max_value); } ele_next.find("." + cur_cli + " .ti_tx input").val(max_value); } else { cur_time = cur_time - step_size; if (cur_time < 10) { cur_time = "0" + cur_time; } ele_next.find("." + cur_cli + " .ti_tx input").val(cur_time); } } } function change_mins(cur_ele, direction) { var cur_cli = "mins"; var cur_mins = Number(ele_next.find("." + cur_cli + " .mi_tx input").val()); var ele_st = 0; var ele_en = 59; var step_size = Number(settings.step_size_minutes); if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') { if (cur_mins + step_size > ele_en) { ele_next.find("." + cur_cli + " .mi_tx input").val("00"); if(settings.overflow_minutes){ change_time(null, 'next'); } } else { cur_mins = cur_mins + step_size; if (cur_mins < 10) { ele_next.find("." + cur_cli + " .mi_tx input").val("0" + cur_mins); } else { ele_next.find("." + cur_cli + " .mi_tx input").val(cur_mins); } } } else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') { if (cur_mins - step_size <= -1) { ele_next.find("." + cur_cli + " .mi_tx input").val(ele_en + 1 - step_size); if(settings.overflow_minutes){ change_time(null, 'prev'); } } else { cur_mins = cur_mins - step_size; if (cur_mins < 10) { ele_next.find("." + cur_cli + " .mi_tx input").val("0" + cur_mins); } else { ele_next.find("." + cur_cli + " .mi_tx input").val(cur_mins); } } } } function change_meri(cur_ele, direction) { var cur_cli = "meridian"; var ele_st = 0; var ele_en = 1; var cur_mer = null; cur_mer = ele_next.find("." + cur_cli + " .mer_tx input").val(); if ((cur_ele && cur_ele.hasClass('action-next')) || direction === 'next') { if (cur_mer == "AM") { ele_next.find("." + cur_cli + " .mer_tx input").val("PM"); } else { ele_next.find("." + cur_cli + " .mer_tx input").val("AM"); } } else if ((cur_ele && cur_ele.hasClass('action-prev')) || direction === 'prev') { if (cur_mer == "AM") { ele_next.find("." + cur_cli + " .mer_tx input").val("PM"); } else { ele_next.find("." + cur_cli + " .mer_tx input").val("AM"); } } } // handle clicking on the arrow icons var cur_next = ele_next.find(".action-next"); var cur_prev = ele_next.find(".action-prev"); $(cur_prev).add(cur_next).on("click", function() { var cur_ele = $(this); if (cur_ele.parent().attr("class") == "time") { change_time(cur_ele); } else if (cur_ele.parent().attr("class") == "mins") { change_mins(cur_ele); } else { if(settings.show_meridian){ change_meri(cur_ele); } } }); }); }; }(jQuery));