Introduction
This plug-in makes an input box background image clickable and handles the click event by a callback function. It is useful when you want a good user
experience of the web page.
Background
jQuery is a great JavaScript library. I have been long time looking forward to writing a plug-in to it. When I was developing
a web application for a digital media advertising system, finally I got an opportunity to write one which is worthy of it.
Adding background image to an input box is very simple, just use css. Making the image clickable is not difficult, either.
Add a div element overlapping the image and attach a click event to the div element, then it is OK.
Though it looks that it is very easy, there are still issues to fix when it comes to browser compatibility and making a jQuery plug-in.
The code of the plug-in
Before going on, we have to get to know what a jQuery plug-in looks like. Here
there is a good tutorial.
According to jQuery, there are two kinds of structures:
$.fn.myPlugin = function() {
};
(function( $ ) {
$.fn.myPlugin = function() {
};
})( jQuery );
Personally I like the second structure. In this article I'll use the second one.
Let's first take an overall look at the plug-in:
(function($) {
$.fn.addClickableBackgroundImage = function(params) {
params = $.extend({ alignTo: 'right' }, params);
this.each(function() {
var input = $(this);
if (input.is(':input[type=text]')) {
var inputPos = input.position();
var inputWidth = input.width();
var inputOuterHeight = input.outerHeight();
var imgWidth = input.height();
var imgHeight = imgWidth;
input.css({
'background': 'url(' + params.imageSrc + ') ' + params.alignTo + ' no-repeat',
'background-size': imgWidth + 'px ' + imgHeight + 'px'
});
var div = $('<div/>').appendTo($('body'));
var divLeft, divTop;
if (params.alignTo.toLowerCase() == 'left') {
divLeft = inputPos.left + (inputOuterHeight - imgHeight) / 2;
} else if (params.alignTo.toLowerCase() == 'center') {
divLeft = inputPos.left + (inputWidth - imgWidth) / 2
} else {
divLeft = inputPos.left + inputWidth - imgWidth + (inputOuterHeight - imgHeight) / 2;
}
divTop = inputPos.top + (inputOuterHeight - imgHeight) / 2;
var img = $('<img />');
img.bind('load', function () {
div.width(imgWidth);
div.height(imgHeight);
div.offset({
left: divLeft,
top: divTop
}).css('cursor', 'pointer');
div.bind('click', function () {
if (typeof params.callback == 'function') {
params.callback.call(this, input.attr('id'));
} else if (eval('typeof ' + params.callback) == 'function') {
eval(params.callback + '.call(this, "' + input.attr('id') + '")');
} else {
alert('Callback "' + params.callback + '" is not a function, or does not exist.');
}
});
});
var imgStyle = 'visibility:hidden;opacity=0';
if ($.browser.msie) {
imgStyle = 'opacity=0;filter:alpha(opacity=0);'
}
img.appendTo(div).attr({
src: params.imageSrc,
width: imgWidth,
height: imgHeight,
style: imgStyle
});
}
});
return this;
};
})(jQuery);
In the plugin, I first set the default position of the image to "right". If user sets the alignTo property of params object,
it will be overidden. See How to Use section.
Plug-in user may select more than one input box. This is the reason why I use this.each function to iterate each element in the user selection.
User may also select all elements of input type by using $(':input'), which may include buttons, check boxes, etc. So it is necessary to use
input.is(':input[type=text]') to filter.
Attaching a background image can be done by simply changing its CSS background style.
But it is not clickable right now. And background-size style applies to CSS3 and later. So it is safe to make an image that fits well into the input boxes.
Then I make a div element with the width and height being equal to the height of the input box, and move it to the position specified by property
alignTo (left, right or center). For browsers such as Firefox and Chrome,
it is OK now if attaching a handler to the click event of the div element. But IE does not let it go, since IE seems to ignore the div if
it contains nothing.
There are 2 ways to fix this IE issue. The first one is add some  's into the div. But how many  's
to add? It involves text metrics. The second one is add the same image into the div and make it invisible. I am going the second way.
But there is browser compatibility issue in making the image inside the div invisible. I tried display:none, but it does
not work with IE. I tried visibility:hidden, again, it does not work with IE. Finally I came to the current solution,
thanks to W3 Schools.
To bind the click event handler to the div element, it is needed to detect if user passes into the params the handler function object or function name,
and detect if the function exists.
How to use it
The following code shows how to use the plug-in.
$(':input').addClickableBackgroundImage({
imageSrc: 'add16x16.png',
alignTo: 'right',
callback: callbackFn
});
function callbackFn(inputId) {
alert(inputId)
}
When the background image is clicked on, an alert box will popup, showing the relevant input box id with the help of the callback function. See the following screenshot:
Possible Issues
- This plug-in is built with jQuery version 1.7.1, I did not test it on other versions.
- I tested it on Firefox 12.0, Chrome 19.0 and IE 8.0, all on Windows 7. I am not sure if it is working with other browsers on other operating systems.
Interested readers, please kindly let me know of any issues.