How to mimic Twitter slides on Safari Mobile

Last night, during our local NSCoders meeting, one of my fellow coders asked me how to replicate some functionality using CSS. It turned out that the functionality required more JavaScript than CSS.

In Twitter the user can slide a twit to show some controls that relate to that twit.  Jorge wanted to imitate this behaviour. After a fast search I explained him how to “bind” some JavaScript to the touchmove and touchend events. This morning, remembering the question I tried to code some fast example implementing a similar functionality.

Basically the user initiates an slide on an element of the list. When the element has been slided past a point it opens completely, revealing the controls beneath.

Thankfully I found here an example on how to mimic the sliding using both touch events and CSS transforms. This sample, in turn, referred to this other. Based on their code I managed to get mine working in a couple of hours. You can point your iPhone to http://www.forcen.com/tests/slide/ to see it in action. For simplicity all of the css, javascript and html are on the same page. The only external dependency is jQuery.

The markup

The HTML for this example is simple:

Each item is contained into a div, that will be the element that is slided.

<ul id="items">
    <li>
        <div id="2323232">
            <strong>first entry</strong><br />An example
        </div>
    </li>
    <li>
        <div id="2454532">
            <strong>second entry</strong><br />of how to imitate
        </div>
    </li>
</ul>

I only have a control bar that will be moved into place when the user starts a move over an entry. The holder is for keeping the  control bar hidden:

<div id="controlsHolder">
<ul id="controls">
	<li><img id="boton1" src="_imgs/b1.png" alt="" /></li>
	<li><img id="boton2" src="_imgs/b2.png" alt="" /></li>
	<li><img id="boton3" src="_imgs/b3.png" alt="" /></li>
</ul>
</div>

The Event Handlers

Now the JavaScript: At load time I bind the touch events to the code that will handle the movement of the item.

The touchstart event is generated when the user touchs on an item. Using jQuery bind it to all div elements with class “content”. The called function will not only initiate the controls bar but it’ll also close any open element whenever the user touchs on any element of the list.

$('div.content').bind(
    'touchstart',

    // whenever the user starts a touch event
    // on this kind of element...
    function(event) {

        // I close any open slider...
        hideControls();

        // and move the controls behind
        // the element touched by the user.
        setControls(event.target);

        // right now, the element is "closed"
        isOpen = false;
);

While the user is moving the element Safari will call this code:

$('div.content').bind(
    'touchmove',
    function(event) {
            // jQuery will send me the element
            // affected by the event
        var el = event.target,
            // this is a jQuery event object, so in order
            // to get the touch parameters I need to
            // access the originalEvent param.
            touch = event.originalEvent.touches[0],
            curX = touch.pageX - this.offsetLeft - 25;

        // we don't want the Safari's standard
        // behaviour for this kind of event.
        event.preventDefault();

        // we're near the left, do nothing.
        if(curX <= 0) { return; }

        // user's moved the element past a point,
        // so I make it slide completely to the left
        if(curX > 150) {
            showControls(el);

            // now the element is open.
            // the touchend handler needs to know it.
            isOpen = true;
            return;
        }
        // otherwise I move the element
        // to follow the user's gesture
         el.style.webkitTransform = 'translateX(' + curX + 'px)';
    }
);

Finally, the touchend event will be send when the user lift ups the finger. This event will be sent regardless of the point where’s the user’s stopped the gesture. And regardless of our code moving the element out of the viewport. So we need to know if the element is “open” or not.

$('div.content').bind(
    'touchend',
     function() {
        // only if our code hasn't been called...
        if(!isOpen) {
            // we move the element back to left.
            doSlide(this, 0);
         }
   }
);

This is just an example function that will be called when the user touchs the mail icon on the tools bar.

$('#boton3').click(doMail)

The Slider Code

The functions that show or hide the controls are, finally, fairly simple. They only need to move the controls bar behind another object and apply a simple CSS transition.

Why a transition instead of a jQuery animation?. In iPhone the CSS transitions are handled bu the GPU, so they are more swift and “natural”. Note the this transitions will not be as smooth on Android’s version of WebKit. Even, in some versions of Android there’ll be no animations at all.

// this function perfoms the sliding of the element
// using CSS3 transforms.
function doSlide(el, numPos) {
    el.style.webkitTransition = '-webkit-transform 0.3s ease-in';
    el.style.webkitTransform = 'translateX(' + numPos + 'px)';
}

// this function is called on touchstart.
// it "moves" the controls bar into the <li>
// that contains the <div> touched by the user.
function setControls(elDIV) {
    $(elDIV).closest('li').append($('#controls'));
}

// this just slides the element away to the right
function showControls(elDIV) {
    // I'm gonna need the refnum of the entry for
    // the functions called from the controls bar.
    numCurItem = elDIV.id;
    // slide the div way out to the right...
    doSlide(elDIV, ($(elDIV).outerWidth(true) + 50));
    // and store the currently open div in a var.
    elContent = elDIV;
}

// here we slide the "open" element back to the left
function hideControls() {
    if(elContent != null) {
        doSlide(elContent, 0);
        elContent = null;
    }
}

Conclusion

So, this is what happens when you mix coders and beer and laughs. You learn some interesting things and get cred points in the process. You can use a similar effect in a desktop web app, by implementing a draggable object like in the css-tricks.com sample.

BTW, the icons are from IconDock.