/**
* @author Sajjan Sarkar
*/
(function($)
{
$.fn.timefield = function(options)
{
//Public Methods
var methods = {
/** Initializes the timefield */
init : function(options)
{
return this.each(function()
{
/** Txt entry is from RIGHT TO LEFT */
this.style.direction = "rtl";
/** Cache for performance*/
var $this = $(this);
/** bind listeners */
$this.bind('keydown.timefield', helpers.eventHandlers.keyDownHandler);
$this.bind('keyup.timefield', helpers.eventHandlers.keyUpHandler);
$this.bind('blur.timefield', helpers.eventHandlers.blurHandler);
});
},
/** removes all timefield effects**/
turnOffTimeField : function(content)
{
return this.each(function()
{
this.style.direction = "ltr";
var $this = $(this);
$this.unbind('.timefield');
});
}
};
/** Private methods */
var helpers = {
eventHandlers : {
/** On key down, check if the pressed key is valid else dont show it.
* acts as mask
* */
keyDownHandler : function(event)
{
if (!helpers.utils.isValidKeyStroke(event))
{
event.preventDefault();
event.stopPropagation();
}
},
/**
* When this is called the keydown event would have already rendered the
* key stroke, so apply the padding with zeros.
* */
keyUpHandler : function(event)
{
var keyCode = event.keyCode;
/** check if a special key was pressed */
if ($.inArray(keyCode, constants.KEYS.SPECIAL_KEYS_TO_IGNORE) != -1)
return;
/** did this on key up instead of keydown as its easier coz the text has rendered */
helpers.utils.applyPadding(helpers.utils.getEventSource(event));
},
/**
* On blur, check the validity of the enterred value based on selected settings.
* Could not do this on change as most browsers dont fire the change event
* if the value has changed programatically.
*
* If the time is invalid, call the specified(or default) onError handler
* */
blurHandler : function(event)
{
helpers.utils.getEventSource(event).value = jQuery.trim( helpers.utils.getEventSource(event).value );
if (!helpers.utils.isValidTime(helpers.utils.getEventSource(event).value))
{
settings.onError.call(helpers.utils.getEventSource(event));
}
}
},
utils : {
/**
* This function returns true if the enterred key is a number, a colon or one of the allowed special keys.
* */
isValidKeyStroke : function(event)
{
var keyCode = event.keyCode;
/** check if a special key was pressed */
if ($.inArray(keyCode, constants.KEYS.SPECIAL_KEYS_TO_IGNORE) != -1)
return true;
/** Only allow numbers and the colon key */
if ((!event.shiftKey && (constants.KEYS.CHARACTER_ZERO <= keyCode
&& keyCode <= constants.KEYS.CHARACTER_NINE || constants.KEYS.KEYPAD_ZERO <= keyCode
&& keyCode <= constants.KEYS.KEYPAD_NINE))
|| (event.shiftKey && keyCode == constants.KEYS.COLON))
{
return true;
}
return false;
},
/**
* This function pads the values with zeroes and colons.
* */
applyPadding : function(textBox)
{
var val = textBox.value;
if (val != "")
val = parseInt(textBox.value.replace(":", ""), 10) + "";
if (val.length > constants.NO_OF_CHARACTERS_WITHOUT_COLON)
{
val = val.substring(val.length - constants.NO_OF_CHARACTERS_WITHOUT_COLON);
}
switch (val.length)
{
case 0:
val = val;
break;
case 1:
val = "00:0" + val;
break;
case 2:
val = "00:" + val;
break;
case 3:
val = "0" + val.substring(0, 1) + ":" + val.substring(1);
break;
case 4:
val = val.substring(0, 2) + ":" + val.substring(2);
break;
}
//$(textbox).blur();
//$(textbox).focus();
/**
* mobile browsers seem to not place the caret in the correct place
* after the padding of zeroes, and IE8 doesnt support
* setselection range but works fine without it.
*
* The basic idea is to add an extra space after the last digit
* and "select" it,ensuring that the caret is in the correct position
*
* */
if(textBox.setSelectionRange)
{
textBox.value = val+" ";
textBox.setSelectionRange(5, 6);
}
else
{
textBox.value = val;
}
return;
},
/**
* This function returns true if the enterred time is
* a valid time based on the specified(or default) settings,
* else returns false.
* */
isValidTime : function(strTime)
{
if (strTime == "")
return true;
var regex = constants.REGEX.TWENTY_FOUR;
switch (settings.hourFormat)
{
case constants.HOUR_FORMATS.TWELVE:
regex = constants.REGEX.TWELVE;
break;
case constants.HOUR_FORMATS.TWENTY_FOUR:
regex = constants.REGEX.TWENTY_FOUR;
break;
}
return regex.test(strTime);
},
getEventSource:function(event)
{
return event.target || event.srcElement;
}
}
};
/**Constants*/
var constants = {
/** Only 2 formats supported now.*/
HOUR_FORMATS : {
TWELVE : "12",
TWENTY_FOUR : "24"
},
KEYS : {
CHARACTER_ZERO : 48,
CHARACTER_NINE : 57,
KEYPAD_ZERO : 96,
KEYPAD_NINE : 105,
BACKSPACE : 8,
TAB : 9,
ENTER : 13,
COLON : 186,
SPECIAL_KEYS_TO_IGNORE : [
8, /**BACKSPACE*/
9, /**DELETE*/
46, /**TAB*/
40, /**DOWN ARROW*/
39, /**LEFT ARROW*/
38, /**UP ARROW*/
37 ,/**LEFT ARROW*/
16 /** SHIFT*/
]
},
NO_OF_CHARACTERS_WITHOUT_COLON : 4,
REGEX : {
TWELVE : /^([0-1]?[0-2])([:][0-5]?[0-9])?$/,
TWENTY_FOUR : /^([2][0-3]|[0-1]?[0-9])([:][0-5]?[0-9])?$/
}
};
// Create some defaults, extending them with any options that were provided
var settings = $.extend( {
'hourFormat' : '24',
'onError' : function()
{
this.value="";
}
}, options);
// Method calling logic
if (methods[options])
{
return methods[options].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof options === 'object' || !options)
{
return methods.init.apply(this, arguments);
} else
{
$.error('Method ' + options + ' does not exist on jQuery.timefield');
}
};
})(jQuery);