Opera mobile window chooser, recreated with jQuery

It’s always fun to play with jQuery especially when you are trying to recreate something that you enjoy using. One such thing is window chooser in Opera Mobile browser where opened windows are positioned below each other and only a portion of each window is visible. The one on the top is current window that is fully visible. Clicking on those windows is followed by some nice effect.

View demo

Our “windows” are nothing more than simple unordered list. Each LI element can have any content, as you can see in the demo. Initially the first LI element will be “the chosen window”.

<ul id="container">
    <li class="current"></li>
    <li></li>
    <li></li>
    <li></li>
</ul>

On the very beginning we define how much each window will be hidden and how much it will slide to the left and right. Next, we assign ID to each window that will be needed later in the process and position them below each other.

var itemWidth = $("#container li").width();
// hide 50% of each window
var itemPosition = itemWidth * 50 / 100;
// slide each window 60% if its width    
var itemMove = itemWidth * 60 / 100;        

// move windows below each other and assign ID to each
$("#container li").each(function(i) {
    $(this).attr("id", i).css("z-index", 100 - i).css("left", itemPosition * i);
});

Now the main part. When user clicks on a window, several things should happen. First we determine the position of a clicked window and the previsouly chosen one. If clicked window is on the left side of the chosen window, all windows before the clicked one will slide to the left. Analogously, if clicked one is on the right side of the chosen window, all windows after the clicked one will slide to the right.

$("#container li").click(function(e) {
    // Get id's of the current window and the one that user clicked on
    var currentID = parseInt($(".current").attr("id"));
    var clickedID = parseInt($(this).attr("id"));

    if (currentID != clickedID) {
        if (clickedID > currentID) {
            // slide windows to the left
        }
        else {
            // slide windows to the right
        }
    }
});

Here’s how we slide windows to the right. We take the ID of the clicked window (and add 1 to prevent clicked window to slide) and loop through the collection of windows to the end. We then first slide each windows to the right, move them behind clicked window (with z-index) and slide them back to the left.

var i = 1;
var total = $("#container li").length;
for (j = clickedID + 1; j <= total; j = j + 1) {
    $("#" + j).animate({ "left": "+=" + itemMove * i + "px" }, 500);
    $("#" + j).animate({ "left": "-=" + itemMove * i + "px" }, 300);
    $("#" + j).css("z-index", currentZ - i);
    i = i + 1;
}

Believe it or not, left sliding is more complex than right sliding. The reason for this is in the fact that windows will be sent to the back immediately upon clicking, so we need to postpone changing z-index for sliding windows to the moment when they are on the leftmost position. Then we can slide them back. We do this in the loop that will iterate from the first window one the left of the clicked one, all to the fist window in the collection.

var i = 1;
var total = clickedID - currentID + 1;
for (j = clickedID - 1; j >= 0; j = j - 1) {
    $("#" + j).animate({ "left": "-=" + itemMove * (i) + "px" }, 500);
    $("#" + j).animate({ "left": "+=" + itemMove * (i) + "px" }, 300);
    i = i + 1;
}
var i = 1;
setTimeout(function() {
    for (j = clickedID - 1; j >= 0; j = j - 1) {
        $("#" + j).css("z-index", total - i);
        i = i + 1;
    }
}, 500);

Now, before we slide windows, we need to remove class .current from the old “chosen one” and assign it to the clicked window. We’ll also postpone this to the moment when windows reach their leftmost/rightmost positions.

var currentZ = 99;
var current = $(this);
setTimeout(function() { $(".current").removeClass("current"); current.css("z-index", currentZ).addClass("current"); }, 500);

At the end, we have one issue here. If windows contain links user might think they can click on the link even ehen they are semi-hidden. In order to fix this issue we prevent default click action by adding e.preventDefault() just below the if statement.

if (currentID != clickedID) {
    e.preventDefault();
    ...

We can also style links as normal text so that there’s no doubt if there’s anything clickable in semi-hidden windows. This way users can access the content in chosen window only.

View demo

I am somehow sure that this can be optimized so if you know the way, shoot it! If I find some free time (which is unlikely) I will create a plugin. Above all it was fun to play with jQuery after such a long time.