tags:

views:

47

answers:

3

I came across this control while using a webapp (this in invite-only beta) and liked the UI interaction. The webapp was built using prototype/scriptaculous, and we typically use jQuery when building our web apps.. my question is, has anyone seen a jQuery equivalent to this UI element?

A couple of the nice things I like about this approach, instead of the typical radioset approach, is the animated sliding effect of the switch button and still being able to slide on a double-click and the resize cursor.

Since I don't have a working example of the element, I've attached a link to view a screen cap of it in action. :)

http://www.youtube.com/watch?v=kdyBodu4bSM

What I'm looking for is a jQuery plugin that can accomplish the same thing.. or a code snippet of something like this in jQuery. Thanks!

A: 

Check this out: http://papermashup.com/jquery-iphone-style-ajax-switch/

That should be exactly what you want. Or at least easily modifiable. Click "DEMO" further down the page to see it in action.

And for other interesting JQuery plugins check out these links: 40 useful JQuery Plugins: http://www.smashingmagazine.com/2010/04/27/45-useful-jquery-techniques-and-plugins/

20 Awesome JQuery buttons: http://speckyboy.com/2010/05/26/20-awesome-jquery-enhanced-css-button-techniques/

I constantly refer to them :)

KennyCason
Thanks for the links.. This is a good looking plugin but it is really just a toggle using animation, it doesn't actually offer a drag feature.. so, its very similar to what we have now. But, thank you for the link! I'd been to the smashingmag link a few times, always a good read and the speckyboy link was cool too.. thanks again
revive
oh, ok. i wasn't aware that the "draggability" was what you were specifically looking for. Though I have to say from a user stand point the simple click action of the one I provided may be easier. But i'll keep looking around, or just make one myself! :D
KennyCason
+2  A: 

Well, it's certainly not easy to make yourself. Not easy, but quite fun. This is my first attempt at creating a plugin so please excuse the poor code quality. The code uses (but is not an extension of) jQuery UI. Specifically, it uses the draggable component for the handle, and some UI CSS classes.

This is certainly a work in progress. It is by no means finished. These are the things I'd like to see done before declaring this thing done:

  1. Keyboard control for moving the handle, for accessibility reasons
  2. Implement WAI-RIA standards, again for accessibility
  3. Set up more options, maybe even events
  4. Refactor the code into something a little more manageable.

The first two are very important, and is the reason why this code shouldn't be used yet. You are, however, welcome to hack around the code and play around with it. All suggestions on how this thing might be made to work better are welcome.

Live demo: http://jsfiddle.net/RDkBL/7/

(function($) {
$.fn.slideButton = function(options) {
    // Settings
    var settings = $.extend({
        slideSpeed: 10,
        revertSpeed: 5,
        labelWidth: 0
    }, options);

    this.each(function() {
        var container = $(this);
        var label = container.children('label');
        var input = container.children(':radio');
        var maxWidth = 0;

        if (label.length != 2 || input.length != 2) {
            throw new Error("The container must contain two radio buttons and two labels");
        }

        // move() does the animation associated with
        // state changing for the button
        function move(direction, speed) {
            var amount = direction === 'right' ? halfWidth : -1;
            var duration = (direction === 'right' ? halfWidth - handle.position().left : handle.position().left) * speed;

            handle.animate({
                left: amount
            }, duration);

            input.eq(direction === 'right' ? 0 : 1).attr('checked', true);
        }

        // Handles changing by checking current state
        function updateState() {
            move(handle.hasClass('on') ? 'right' : 'left', settings.slideSpeed);
            handle.toggleClass('on');

            return false;
        }

        // Reverts position - think of this as
        // the opposite of updateState()
        function revert() {
            move(handle.hasClass('on') ? 'left' : 'right', settings.revertSpeed);
            return false;
        }

        // Adding classes and hiding input elements
        container.addClass('ui-sbutton-container ui-corner-all');
        input.addClass('ui-helper-hidden-accessible');

        label.addClass('ui-sbutton-label');

        // Setting label widths - if none set,
        // then loop through all of them and use the biggest
        if (settings.labelWidth) {
            maxWidth = settings.labelWidth;
        } else {
            label.each(function() {
                var w = $(this).outerWidth();
                if (w > maxWidth) {
                    maxWidth = w;
                }
            });
        }

        // Padding was useful for finding largest width,
        // but will now interfere when setting explicit widths
        label.width(maxWidth).css({
            'padding-left': 0,
            'padding-right': 0
        });

        // Getting all important half width for later use
        var halfWidth = (container.outerWidth() / 2);

        // Very messy chain that does element creation,
        // insertion and event handling all at once
        var handle = $('<a />')
        .addClass('ui-sbutton-handle  ui-corner-all').hover(function() {
            $(this).toggleClass('ui-sbutton-active');
        }).dblclick(function(){
            updateState();
            return false;
        }).appendTo(container).width(maxWidth - 1).draggable({
            containment: 'parent',
            axis: 'x',
            stop: function(event, ui) {
                var left = $(this).position().left;
                if ((left > (halfWidth - 1) / 2 && handle.hasClass('on')) || (left < (halfWidth / 2 - 1) && !handle.hasClass('on'))) {
                    updateState();
                } else {
                    revert();
                }
            }
        });

        // Set up initial state of the button
        if (input.first().is(':checked')) {
            move('right', 0);
        } else {
            handle.addClass('on');
        }
    });

    return this;
};})(jQuery);
Yi Jiang
VERY NICE! And it's always fun using jsFiddle to test code :D Thank you for taking the time to tackle this! I'm learning more everyday and really appreciate the help with this.. as my skill set lies more in the HTML5/CSS3/UX/UI realm.. learning how to extend jQuery is something I'm constantly striving for. I'll play around with the code more, and if you are able/have time to address those concerns you listed,.. I'm more than happy to offer any help that I can. Thanks again!
revive
A: 

Also check out the upcoming jQuery Mobile library. They'll have a control just like that one. Some time late October is when we should first see some output apparently.

Chris Meek
Thanks Chris.. I've been keeping a close eye on jQuery Mobile... eagerly awaiting its release :D thanks!
revive