Archive for 'jQuery'

jQuery Mix Photo Gallery

Recently I coded an interesting photo gallery using jQuery. I’ve named it “jQuery Mix Photo Gallery”. I’ve included the screen-shots here.

You may have a look at the live demo here. The photo gallery is free to download. Here is the download link. You may modify it according to your need and use it in your commercial projects. Please drop a comment if you like it and suggest me how can I make it much better.

JSONP First Timer

You already know ajax is one-man’s-girl, no way to make it work cross-domain(not even subdomain) due to browsers’ same origin policy security restriction. But using ajax is so sleek, you can’t even resist yourself using it under different domains. There is always a way around for everything. Do I sound contradictory? Ajax is based on the XMLHttpRequest and as long as we use it we can’t do cross-domain data transfer. Let’s think something else other than ajax.

We are used to loading images, css, javascript files from other domains and it’s okay if we use any server-side dynamic link as the src, this is a common phenomena on web. For example:

<script type="text/javascript" src="http://www.other-domain.com/dynamic-js.php?id=5&name=Matt"></script>

There is no security restriction including javascript source from different domains, and fortunately enough you can pass GET variables (don’t over-expect for POST) with the url. This is how JSONP (JSON with padding) works, thanks to the open policy for <script> tag. May be you’r already thinking how to implement this idea, hold on! you don’t need to reinvent the wheel.

Here comes jQuery’s $.getJSON(), with this function you can pass url of another domain and get JSON data. Lemme warn you, for the very first time most of you won’t be able to make it work. Here is an example:

$.getJSON("http://www.other-domain.com/dynamic-js.php?id=5&name=Matt&jsoncallback=?",
function(data){
    // your code goes here
});

You need to understand this “jsoncallback=?” bit clearly. From your firebug Net panel you can see the “?” is replaced with “jsonp1277557614558″ (random value on each request).

JSONP Net Panel screen shot

The common mistake you’re gonna do is you expect to see something on firebug’s Console tab, but nothing there, once again JSONP is NOT Ajax request. This is merely an external javascript file being added to your document dynamically, if you don’t believe me on your firebug panel click the JS from Net tab to filter out the JS only(marked in the screen-shot above). You’ll definitely see the JSONP url there. This is the client-side part of $.getJSON(). The confusion still remains with the server-side code.

Back to “http://www.other-domain.com/dynamic-js.php?id=5&name=Matt&jsoncallback=?”, the file being called is dynamic-js.php. Put this one line of code in that file:

<?php print_r($_GET); ?>

And check the Response output from firebug’s Net tab. It’ll be something like:

Array
(
    [id] => 5
    [name] => Matt
    [jsoncallback] => jsonp1277557614558
)

In Ajax when the dataType is json the response from server-side script is just the json string:

{
	// your json data
}

Here is the most important part, unlike ajax for JSONP the $.getJSON() expects the response like:

 jsonp1277557614558({
	// your json data here
})

So you must wrap the json output with jsonp1277557614558( ). If you don’t do it the callback will fail silently without any error, which makes it tough to detect the exact problem. Remember the jsonp1277557614558 is a random string. For php the code will be something like this:

<?php
// your code here
// get the output in an array say $output_array
$jc = $_GET['jsoncallback'];
echo $jc . '(' . json_encode($output_array) . ')';
/*
// For ajax response, simply
echo json_encode($output_array);
// is enough
*/
?>

This is the most crucial thing, most programmers do the mistake for their very first time as there is no clear elaboration on $.getJSON documentation page. FYI, json_encode() function is not available on older version of php. You can get the php class from json.org.

Hope your $.getJSON() is now working! :)

Comments, criticism are most welcome.

jQuery Drop down menu without setTimeout

I worked a lot with drop-down menus like most of you. There are many stable versions of DD menus using pure javascript & CSS or only CSS with cross-browser support and you’ll get them free from many menu maker websites or desktop applications. So I’m not going to reinvent the wheel.

I’m a freaking fan of jQuery and always use it for drop-down menus with my custom jQuery code. It’s a must to use a delay for javascript driven dd menus even for jQuery when you want to give it some effect like slideDown or slideUp (For CSS dropdown menus it’s not possible & thus no need to use delay). I always wished to use jQuery without any setTimeout function for the drop-down menus. And I did it which I’m gonna share with you.

$(function () {
    $("ul>li").hover(function () {
        $(this).find("ul.sub").slideDown('fast');
        $(this).addClass("hover");
        $(this).hover(
        function () {},
        function () {
            $(this).find("ul.sub").slideUp('fast');
        });
    },
    function () {
        $(this).removeClass("hover");
    })
})

Here it is in action

The main tricky part is using hover inside hover function:

$(this).hover(
function () {},
function () {
    $(this).find("ul.sub").slideUp('fast');
});

This removes the mouseover function (first function of hover) when mouse hover into the li so the slideDown does not happen again when the mouse enter into the inner ul/li. Hope that makes sense. You may like to add a delay and do some more fine tunes.

Happy Coding!

Advanced cycle plugin integration

On my another post I mentioned that cycle is a great jQuery plugin. I use it very often for slideshow. Recently I used it on a project where the slideshow had many(20+) wallpaper sized images. So loading time was a great issue.

The default cycle integration includes all the images during page loading which is okay for small images, but highly affects the page loading time for high resolution images. cycle plugin is highly flexible! I fixed the issue by loading images dynamically one after another at the end of each slide, literally before the beginning of each slide.

Here is how I did it:

<div id="slideshow"><!-- slides will be added here --></div>
var gallery = ["images/1.jpg", "images/2.jpg", "images/3.jpg", "images/4.jpg", "images/5.jpg", "images/6.jpg", "images/7.jpg", "images/8.jpg", "images/9.jpg", "images/10.jpg", "images/11.jpg", "images/12.jpg", "images/13.jpg", "images/14.jpg"]; // and so on.. array of images
// Array clone function.
Array.prototype.clone = function () {
    var arr = new Array();
    for (var property in this) {
        arr[property] = typeof(this[property]) == 'object' ? this[property].clone() : this[property];
    }
    return arr;
}
var gal = null; // gal should be global as I'll use it inside onBefore function
$(function () {
    gal = gallery.clone(); // cloning the array is not mandatory, but doing so will keep the main array unchanged.
    $('#slideshow').empty().append('<img src="' + gal.pop() + '" /><img src="' + gal.shift() + '" /><img src="' + gal.shift() + '" />') // adding the last, first and second element of the array to the slideshow div, then start the cycle plugin.
    .cycle({
        startingSlide: 1,
        // this is required (1 is the 2nd slide) as the first slide is the last element of the array. if you use manual next/prev button clicking on #prev will show the first element.
        before: onBefore, // loads the next image at the beginning of each slide. (NOT all at once)
        next: "#next",
        prev: "#prev"
    });
    var totalSlideCount = 1 + gal.length;
    function onBefore(curr, next, opts, fwd){
        // at first addSlide is not defined, so we should return.
	if (!opts.addSlide) return;
	// if all the elements of the array are added no need to add them again!
        if (opts.slideCount == totalSlideCount) return;
	// shift or pop from slide array
        var nextSlideSrc = fwd ? gal.shift() : gal.pop();
	// add next slide
        opts.addSlide('<img src="' + nextSlideSrc + '" />', fwd == false);
    }
});

In this code above, cloning the array is optional. I used it as I needed the main array for later use. Probably you know if you use the global array reference to a local variable and apply pop()/shift()/push() functions to the local variable, the global one will be affected. cos the local variable is just a reference to the address of the global array variable.

At first the last, 1st and 2nd elements of the array are added to the #slideshow div and the cycle is started from the 2nd slide. Before starting of each slide onBefore function is called. The onBefore function adds new slide to the slideshow and stops when all the array elements are added to the slide.

You may use it for small size images also if you need to improve the page loading duration.

IE6 fix for select box over absolute positioned element

IE6 sux. General css/javascript hover drop-down menu uses a div or ul with position:absolute. No matter how much you increase the value of z-index the select box (windowed element) will always remain on top most – yes only on a special browser, Internet Explorer 6. The reason is IE6 considers select element as windowed element and keeps it always on top layer.

IE6 select box over div

Solution is using iframe on top of select element, as iframe is also a windowed element placing it on top of select box fix the problem.

IE6 select box over div prob fixed using iframe

Here is the typical HTML code for this drop-down menu:

<div class="top-menus" style="left: 221px; top: 127px;">
<iframe frameborder="0" scrolling="no" align="bottom" marginheight="0" marginwidth="0" src="javascript:'';" style="height: 200px;"></iframe>
    <ul>
      <li><a href="#">Bracelets</a></li>
      <li><a href="#">Rings</a></li>
      <li><a href="#">Earrings</a></li>
      <li><a href="#">Necklaces</a></li>
    </ul>
</div>

The inline css is calculated using jQuery offset() function. FYI, you can easily get the width,height,left,top position of any element using jQuery(“element”).offset(). Make sure the width and height of the iframe is exactly same of it’s overlying UL element. If you apply any border to the UL, you have to consider that during calculating the proper width/height of the iframe.

This is the sample jQuery code:

var timer = null; // global
$("#top-nav a").hover(function(){
	clearTimeout(timer);
	$("#top-nav a:not('.cur')").removeClass("selected");
	$(this).addClass("selected");

	var o = $(this).offset();
	var left = o.left + 1; // 1px extra for border
	var top = o.top + 32; // 32px for placing it just below the horizontal menu
	if($(".top-menus").length){
		if(left == $(".top-menus").offset().left)
			return;
		else $(".top-menus").remove();
	}

	$("body").prepend('<div style="left:'+left+'px;top:'+top+'px;" class="top-menus"><iframe src="javascript:\'\';" marginwidth="0" marginheight="0" align="bottom" scrolling="no" frameborder="0"></iframe><ul>'+html+'</ul></div>');
		$(".top-menus").find(".parent, .child").remove();
		var hi = $(".top-menus").find("ul").height();
		$("iframe").height(hi + 2); // extra 2px for border

}, function(){
	clearTimeout(timer);
	timer = setTimeout(function(){$("body").find("iframe,.top-menus").remove(); $("#top-nav a:not('.cur')").removeClass("selected");},300);
});

$(".top-menus").live("mouseover",function(){
	clearTimeout(timer);
}).live("mouseout",function(){
	clearTimeout(timer);
	timer = setTimeout(function(){$("body").find("iframe,.top-menus").remove(); $("#top-nav a:not('.cur')").removeClass("selected");},300);
});

I know this code won’t exactly fulfill your requirement, you can get the main idea from this and write your own code yourself. You can see it in action on www.trendtogo.com.

jQuery cycle plugin as carousel

The jQuery cycle plugin is really amazing! I love this plugin for its huge options for image/div slide show. Right now I’m working on a project which has 3 slideshow on one page. One is simple fade effect with text divs, another one is also fade effect with div + image + text and play/pause, next/back option. The third one is a simple carousel with continuous play mode.

I implemented the first two easily with cycle plugin. But I got stuck with the carousel one. The play and the next state is fine as I used the “scrollLeft” fx. The problem is when I click previous button the fx should be “scrollRight” and not “scrollLeft”. I thought it may need a little complex customized function to do this job of applying different transition effect on previous and next event. I had no clue for it. Even no help from google search! I do not like using a lot of plugins at a time. I know there is jCarousel / jCarousel lite plugin for this, but I still believe there must be a way for doing this with cycle.

It took several hours to find out the simple solution. It’s already inside the cycle plugin, but kinda hidden! I am using the “scrollHorz” fx effect and it is fixed now. WOW! again I discovered that “cycle” is really a marvelous plugin of jQuery.

Here is the example on the malsup site: http://www.malsup.com/jquery/cycle/scrollhv.html

This is the simple code I used:

$('#carousels').cycle({
    prev: '#left-arrow',
    next: '#right-arrow',
    pause: 1,
    fx: 'scrollHorz',
    timeout: 6000
});

IE6 png alpha transparency fix for dynamically loaded images via ajax

IE6 is always a nightmare for web developers. The most painful drawback is it does not support the alpha transparency of transparent png images and you know how to solve this problem using iepngfix or jquery.pngFix.js.

You must be thinking.. what is new in my post then!! Have you ever used any of them for dynamic png images? Some people call it “Loading an image via ajax”. Let me explain what I mean by “dynamic png images”.. say you have a page where clicking on a link does not reload the page, but load a transparent/semitransparent png image. Most specifically, I was working on a project where user types some text in a text box, it is converted to transparent png image on the fly using php and then it is displayed inside a div which has a graph-paper like background-image. This whole thing is done without reloading the page at all.

It looks okay on FF, safari, IE7 but on IE6 the transparent portion looks Grey. The iepngfix.htc script didn’t help, cos it only works on the images which are loaded and showed at the beginning of page loading. After the page is fully loaded and you load another png image using ajax this script won’t work. But I could not do that for my project as it is meant to be loaded dynamically using ajax for the sake of advanced user experience.

I started googling for it, no luck. Finally I modified a portion of code used in the iepngfix.htc file and fixed the problem using this simple javascript code. (FYI, I was using YUI so only the browser checking part is done using it, you can use jQuery or pure javascript for browser detection)

var textImage = new Image();
textImage.src = "text.png"; // src of the png image. okay if not ie6
if (YAHOO.env.ua.ie > 5 && YAHOO.env.ua.ie < 7) { // if IE 5+ or 6 or 6+
    var timg_src = textImage.src;  // textImage
    var new_img = new Image();  // just as a preloader
    new_img.src = timg_src;

    new_img.onload = function(){ // remember, the image is being loaded dynamically, so apply the filter after it is loaded.
        var ti = document.getElementById("textImage"); // the ID of the img tag where it'll be loaded
        ti.style.width = new_img.width; // you can get the width/height of image after it is fully loaded
        ti.style.height = new_img.height; // and you must "DEFINE" the image height/width. "auto" height/width won't work!

        // This is it. apply the filter :)
        ti.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + timg_src + "', sizingMethod='scale')";
        ti.setAttribute('src', 'blank.gif'); // don't forget this part. the image src is replaced with a blank gif image.
    }
}

Here is another version of the code which is not for dynamic images. It’s alternative of iepngfix.htc. In some cases you may not like using iepngfix.htc, rather want to control it yourself. For example if your page has hundreds of png images which are not transparent and only a few images that are transparent, in this case using iepngfix.htc will make the whole process too slow. I applied a pseudo class “png” to all png images & divs with png background image with fixed height & width and applied this simple jQuery code:

$(window).load(function(){ // after all the images are loaded
    if ($.browser.msie && parseInt($.browser.version.substr(0, 1)) < 7) { // ie6 or 5
        $("img.png").each(function(){
            $(this).css("filter", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + $(this).attr('src') + "', sizingMethod='scale')").attr("src", "images/blank.gif");
        });
        $("div.png").each(function(){
            var bg = $(this).css("backgroundImage");
            bg.match(/^url[("']+(.*\.png)[)"']+$/i);
            bg = RegExp.$1;
            $(this).css("filter", "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + bg + "', sizingMethod='crop')").css("backgroundImage", "none");
        });
    }
});

Hope you’ll find it helpful. Please let me know if you have any better idea.

Using Dreamweaver Spry validation with jQuery ajax form plugin

Writing form validation code manually is a boring task. Not only that, editing or adding new fields each time and modifying the validation code accordingly is such a pain. When Dreamweaver added the Spry form validation with CS3 the nightmare is over. The greatest feature of using it is you can do the form validation work automatically with a couple of mouse clicks and no hand written code! And you can easily change/edit or add/remove the fields.

I know jQuery has simple validation plugin but you have to write the codes for it, which is time consuming. I always use the spry validation of dreamweaver as I learned using it for it’s simplicity. When I tried to use it with the jQuery ajax form submit plugin I got disappointed. It didn’t work! I didn’t stop trying. And finally I found the way which I’m gonna share with you :)

Here is the simple code that you need in the “beforeSubmit” parameter of $.ajaxForm

$("#formID").ajaxForm({
    url: "submit.php",
    beforeSubmit: function(formData, jqForm, options){
        if (Spry) { // checks if Spry is used in your page
            var r = Spry.Widget.Form.validate(jqForm[0]); // validates the form
            if (!r)
                return r;
        }
    },
    success: successFunction,
    complete: completeFunction
});

Hope that’ll help a lot boosting your web development.

Gmail uploader clone with drag drop feature : Free Download with source code

Recently I developed the gmail file uploader clone using jQuery. Here is the online demo.

Gmail uploader clone with drag drop feature screen shot

I added some extra functionalists.
You can see the image thumbnails after the uploading is completed. There is a cross button at top right of each thumbnail, clicking on it will delete the image. If you right click on the image you’ll see a context menu from which you can delete the image too along with replace the existing image option.

The most interesting feature is you can drag drop the thumbnails to change the order. Yes this is essential when you need to maintain the order of images in classified sites after uploading them, also a little modification will let you edit the image order later time by dragging the thumbnails. The image name and the image title is dynamically added in the “updateInfo” form and send(post) via the hidden fields imgs[] and imgComment[]  array. You can easily get the order by php using foreach loop on $_POST['imgs'] field. Just hit the submit button after uploading 2 images and you will see the output on post.php page. (hope that makes sense).

Download it for free in a single zip file

If you have any better example of gmail uploader clone please share the links in comments.

jQuery vs. prototype.js

I’m basically a jQuery developer. I had little knowledge about prototype.js. All I knew is jQuery is better than prototype, so I never got interested about it.

However, for some reason I started a project with prototype.js and each line of code makes it clearer that which one is better. Somehow I finished the project using prototype.js along with scriptaculous.js and effects.js. Everything was fine in IE7 and FF 3. But it breaks in IE6. I was not happy with the unnecessary huge code. For example there is no live event in prototype.js, you can not apply an event to a group of elements with same class (You have to use loop for it), there is nothing like jQuery.animate function by which you can do any css animation (You have to add scriptaculous.js for some pre-built animation effects!) and a lot more limitations.

Even the scriptaculous.js is not that rich, for example using ScrollTo effect you can smoothly scroll to any anchor tag “vertically” only but no way of ScrollTo horizontally(!) in case your page is landscape orianted. Here is the code that I used instead(I found the idea from the source code of ScrollTo function):

var scrollOffsets = document.viewport.getScrollOffsets();
var elementOffsets = $$('div.active ul li')[index].cumulativeOffset();
new Effect.Tween(null,scrollOffsets.left,elementOffsets[0] - lo,function(p){window.scrollTo(p,scrollOffsets.top);});

The equivalend jQuery code is:

$("html,body").animate({
scrollLeft: ($('div.active ul li').eq(index).offset().left - leftOffset) + 'px'
}, "slow", "swing");

There are a lot more examples like this. The summary is the code using prototype.js was 180 lines and the equivalent code using jQuery is now only 160 lines + a lot of mental relief that it would work on all browsers :)

One thing I want to make clear is I have no intention to boost anything. In fact both of them are free.