jQuery Extension: removeClassExcept() method

I came across a question on StackOverflow.com where the user wanted the ability to remove all classes from an element except certain ones.  For example if I had the following element

<div class="aa bb cc dd ee">Lorem Ipsum</div>

How would you go about removing all classes except for “aa” and “bb”?  One way would be to just set the class attribute to the classes you wanted to keep.


$("div").attr("class", "aa bb");

That’s easy enough.  Another way would be to use some built in jQuery methods.


$("div").removeClass().addClass("aa bb");

The previous code would remove all classes and then add back the ones that were needed.  That snippet could be put into a jQuery extension to make it easier to call.


jQuery.fn.removeClassExcept = function (val) {
    return this.each(function () {
        $(this).removeClass().addClass(val);
    });
};

$("div").removeClassExcept("aa bb");

That makes the code look cleaner.  One problem both of these solutions have is they don’t check to see if the class already exists before adding it.  On the Stack Overflow question, Brad Christie proposed a solution to handle the case where you didn’t want to add a class unless it already existed.  The updated extension now takes that into consideration.


jQuery.fn.removeClassExcept = function (val) {
    return this.each(function (index, el) {
        var keep = val.split(" "),  // list we'd like to keep
            reAdd = [],          // ones that should be re-added if found
            $el = $(el);       // element we're working on

        // look for which we re-add (based on them already existing)
        for (var i = 0; i < keep.length; i++){
            if ($el.hasClass(keep[i])) reAdd.push(keep[i]);
         }

         // drop all, and only add those confirmed as existing
         $el
            .removeClass()               // remove existing classes
            .addClass(reAdd.join(' '));  // re-add the confirmed ones
    });
};

Here is a jsFiddle showing the use of removeClassExcept(): http://jsfiddle.net/9xhND/1/

jQuery Extension: removeClassExcept() method

Recreating Google+ Expanding Image Stack

Skip straight to the demo

After taking some time to browse around Google+ I noticed a cool effect on the albums page when hovering over an album. If the album had multiple images in it, the stack would expand to show the first 3 images inside the album. You can see an example of it here: https://plus.google.com/photos/105135327491673313070/albums.

I thought it would be neat to try and reproduce this effect. This example will work in Chrome, Firefox 4+, and Safari 4+.

Step 1 – Get images

The only thing we need to do in step 1 is get 3 images of the same size and put them into a block element.  I grabbed 3 images from my Google+ account and put them in a div with the id of “photo-stack”.

<div id="photo-stack">
    <img src="https://lh3.googleusercontent.com/-khtZ0GBqcOI/Th2kD8vv0ZE/AAAAAAAAACU/rd3t2O6QI-o/s195-c/BVI2008" />
    <img src="https://lh3.googleusercontent.com/-ZpghGAz-jZE/Th2kECfNChI/AAAAAAAAACI/VAtLWAuUbf0/s195-c/photo.jpg" />
    <img src="https://lh4.googleusercontent.com/-xcrH8Z9qHqI/Th2kEMhqQ1I/AAAAAAAAACA/jL8ZZTTpqA4/s195-c/photo.jpg" />
</div>

View Step 1

Step 2 – Stacking

Now that we have our 3 images let stack them on top of each other.  This is accomplished by positioning each of them absolutely on top of each other.


#photo-stack { position: relative;}

#photo-stack img { position: absolute; top: 0; left: 0;}

That looks good, but I want the first image in the DOM to appear on top.  In that case we need to set the z-index of each image.  I am going to use the nth-child property so we don’t have to add classes to each image.


#photo-stack img:nth-child(1) { z-index: 3;}

#photo-stack img:nth-child(2) { z-index: 2;}

#photo-stack img:nth-child(3) { z-index: 1;}

Now the first image is on the top!

View Step 2

Step 3 – Moving

Let’s start working on the animation.  The animation has 3 parts to it: movement of the images, rotation of the images, and the size of the images.

We can handle the movement of the images by using the translate value of the transform property.  We are going to use the nth-child property just like we did in the last step in order to target each image individually.

Translate takes 2 values for the x and y movement.  Since the second image isn’t moving we are only going to move the first and last images.


#photo-stack:hover img:nth-child(1) {
    -webkit-transform: translate(-50px, 0px);
}
#photo-stack:hover img:nth-child(3) {
    -webkit-transform: translate(50px, 0px);
}

View Step 3

Step 4 – Rotating

Now that we have the images moving apart we can rotate the outer image.  Rotate only takes 1 argument for the amount of degrees you want to rotate the element.  Once again the middle image is not being rotated so we will not worry about it.


#photo-stack:hover img:nth-child(1) {
    -webkit-transform: rotate(5deg);
}
#photo-stack:hover img:nth-child(3) {
    -webkit-transform: rotate(-5deg);
}

We are getting close!  View Step 4

Step 5 – Scaling

The images need to grow a little in size when they are spreading apart.  By using the scale property we can pass in a value to change the size of the image (1 being 100%).


#photo-stack:hover img:nth-child(1) {
    -webkit-transform: scale(1.1);
}
#photo-stack:hover img:nth-child(2) {
    -webkit-transform: scale(1.1);
}
#photo-stack:hover img:nth-child(3) {
    -webkit-transform: scale(1.1);
}

View Step 5

Step 6 – Animating

In order to get the transforms to animate when hovering, only 1 line of code needs to be added.  The -webkit-transition line takes 3 arguments: property to animate, amount of time, and animation timeline.  In our case we want to animate the -webkit-transorm property for .25 seconds and have a linear timeline.


#photo-stack img {  -webkit-transition: -webkit-transform .25s linear;}

View Step 6

Step 7 – Cleanup

The look can be cleaned up a little by applying some additional styles.  Now it looks like a real stack of photos!

View Final Demo

Let me know what you thought of the tutorial or if you put this to use on one of your sites!

Recreating Google+ Expanding Image Stack

jQuery Extension: toggleText() method

Skip straight to the demo.

Here’s a situation I have run into multiple times: I have a hidden area that is toggled by a link.  The link will usually say “Show *”, and once it is clicked it will say “Hide *”.  I would usually just check the text when the link is clicked and switch it.  Similar to the following:

$("a").click(function() {
    var $self = $(this);
    if ($self.text() == "Show items")
       $self.text("Hide items");
    else
        $self.text("Show items");
});

It would get tedious to add this to every link that toggled the view on an element.  In order to make it easier on myself I threw together a little extension for jQuery.  You pass it 2 string values representing the text that you would like to toggle.  Here is an example usage that does the same thing as the code block above:

$("a").click(function() {
    $(this).toggleText("Show", "Hide");
});

The extension looks for the first value in the element’s text and if it exists, it is replaced with the second value.  If the first value doesn’t exist in the element’s text, it looks for the second value in the text and replaces it with the first value.   Here is the source:

jQuery.fn.toggleText = function (value1, value2) {
    return this.each(function () {
        var $this = $(this),
            text = $this.text();

        if (text.indexOf(value1) > -1)
            $this.text(text.replace(value1, value2));
        else
            $this.text(text.replace(value2, value1));
    });
};

To see it in action, you can view the demo.

jQuery Extension: toggleText() method

Testing the iOS 4.1 HD video upload to YouTube

Today Apple released iOS 4.1 for the iPhone 4, 3GS, and 3G.  One of the noted features was HD video upload to YouTube.  I have uploaded a couple videos to YouTube in the past and the quality was far from desired.  After the installation I took a quick 20 second video of the view from my porch outside.  I selected the option to upload to YouTube and let the phone go to work.

The upload process was actually pretty quick.  The video is was 6.8 Mb and it took about a minute or 2 to upload.  As soon as it was uploaded it was viewable online which was pretty nice.  Below you will find the video that I uploaded.

The first thing I noticed was that the 720p option was not available to select.  The phone can apparently support up to 720p recording so I am confused as to why it didn’t upload in 720p.  Other than that the video turned out pretty good.  I think this might be a nice feature to actually use in the future.

UPDATE:  It looks like the 720p option is now available.  It must take a little extra time for some processing to happen on the server.  This is exactly what I was looking for when Apple first announced the ability to upload straight to YouTube.

Testing the iOS 4.1 HD video upload to YouTube

Using jQuery and YQL to get an RSS feed from a site

I forgot to post a link to this earlier, but I wrote a blog post on using jQuery and YQL to get an RSS feed from a web site. The code uses YQL to grab the content of the external site and then jQuery to find a link tag pointing to the location of the RSS feed. This is similar to how Firefox displays the RSS feed icon in the address bar.

Check out the full post here.

Using jQuery and YQL to get an RSS feed from a site