views:

2846

answers:

3

Edit: I put this snippet of code in jsbin: http://jsbin.com/eneru


I am trying to let the user resize (only vertically) a DIV element with jQuery. I read about jQuery UI, I tried it, and in some minutes, I had it working. But the library is adding a ~25KB overhead that I would like to avoid, since I only want simple vertical resizing.

So I tried to do it on my own. Here it is the HTML, I am using inline styling for clarity:

<div id="frame" style="border: 1px solid green; height: 350px">
    <div style="height: 100%">Lorem ipsum blah blah</div>
    <span id="frame-grip" style="display: block; width: 100%; height: 16px; background: gray"></span>
</div>

As you can see, there is a little bar under the DIV element, so the user can drag it up or down to resize the DIV. Here it is the Javascript code (using jQuery):

$(document).ready(function(){
    var resizing = false;
    var frame = $("#frame");
    var origHeightFrame = frame.height();
    var origPosYGrip = $("#frame-grip").offset().top;
    var gripHeight = $("#frame-grip").height();


    $("#frame-grip").mouseup(function(e) {
     resizing = false;
    });

    $("#frame-grip").mousedown(function(e) {
     resizing = true;
    });

    $("#frame-grip").mousemove(function(e) {
     if(resizing) {
      frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
     }
    });
});

It works, more or less, but if you drag the bar too fast, it stops following the mouse movement and everything breaks.

It is the first time I try to do something serious (ahem) with JS and jQuery, so I may be doing something dumb. If so, please do tell me :)

+8  A: 

You are doing something dumb: You're trying to do it yourself.

Hear me out, hear me out: Javascript across browsers is a horrible, horrible thing. There are many engines in many versions with many different operating systems, all of which have many subtleties, all of which make Javascript pretty much hell to work with. There is a perfectly good reason why librabries such as jQuery (and their extensions) have exploded in popularity: a lot of great programmers have spent a lot of hours abstracting all these horrible inconsistencies away so we don't have to worry about it.

Now, I am not sure about your user base, maybe you are catering to old housewives that still have dialup. But for the most part in this day and age the 25KB hit on the initial page load (as it will be cached afterwards) for the peace of mind that this is going to work in all browsers consistently is a small price to pay. There is no such thing as "simple" resizing when it comes to Javascript, so you're better off using UI.

Paolo Bergantino
Agreed. If you're already paying the price of bringing in jQuery, bringing in the core and resizable isn't *that* much more load. Additionally, if you know your users will have access to the Internet, you could use the Google Ajax Libraries API to bring in jQuery UI, available at http://code.google.com/apis/ajaxlibs/ - and if your users have already hit a site using it, it'll already be cached, bringing effectively zero additional download at that point.
Brian Arnold
You are right, it's not that much, and I have noted it's hard to get crossbrowser compatibility.Anyway, it's not my site, so I didn't realize that *they are serving TONS of Javascript without minifying or gzipping*. So I compressed everything and now, even with jQuery UI, it's smaller than before! Thank you.
Martín M.
+1  A: 

I agree with Paolo about using UI, but here are some modifications to your code to get it working:

$(document).ready(function(){
    var resizing = false;
    var frame = $("#frame");

    $(document).mouseup(function(e) {
        resizing = false;
    });

    $("#frame-grip").mousedown(function(e) {
        e.preventDefault();
        resizing = true;
    });

    $(document).mousemove(function(e) {
        if(resizing) {
          var origHeightFrame = frame.height();
          var origPosYGrip = $("#frame-grip").offset().top;
          var gripHeight = $("#frame-grip").height();
          frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
        }
    });
});
Emmett
+1  A: 

You can save having a do-nothing handler called when you're not resizing, by only binding the mousemove function when you are actually dragging:

$(document).ready(function(){
    var resizing = function(e) {
        var frame = $("#frame");
        var origHeightFrame = frame.height();
        var origPosYGrip = $("#frame-grip").offset().top;
        var gripHeight = $("#frame-grip").height();
        frame.height(e.pageY - origPosYGrip + origHeightFrame - gripHeight/2);
        return false;
    }

    var stopResizing = function(e) {
        $(document).unbind("mouseover", resizing);
    }

    $("#frame-grip").mouseup(stopResizing);

    $("#frame-grip").mousedown(function(e) {
        e.preventDefault();
        $(document).bind("mouseover", resizing).mouseup(stopResizing);
    });

});

(sample at http://jsbin.com/ufuqo)

Stobor
It doesn't work very well with Chrome 3.0.190.4. That shows that I was trying to reinvent the wheel, crossbrowser compatibility is a pain :P
Martín M.