How To: Prototype Resize Handle
This is just a short post to share some JavaScript that I wrote to be able to add a drag corner to an html element to make it resizable.
I did this using prototype.js. As an example the two divs below have been made resizable. (Go ahead. Drag the bottom right corner around.)
And below is the code that makes it possible. If you take a look at it and read the comments, You'll see that it's actually pretty simple. The thing that had me stuck for a while was asking Prototype how tall or wide something is isn't the whole story. Border and padding add to width and height. I have some code in there that will compensate for that. However, I only covered situations where the border/passing were uniform all the way around. Anyway, love to hear what you think about this.
Div One
<div class="corner" id="DragHandle"> </div>
</div>
<div id="DivTwo" style="position:relative; width:150px; height:75px; border:1px dashed red;">
Div Two
<div class="corner" id="DragHandleTwo"> </div>
</div>
<script type="text/javascript" language="javascript">
function DragCorner(container, handle) {
var container = $(container);
var handle = $(handle);
/* Add property to container to store position variables */
container.moveposition = {x:0, y:0};
function moveListener(event) {
/* Calculate how far the mouse moved */
var moved = {
x:(event.pointerX() - container.moveposition.x),
y:(event.pointerY() - container.moveposition.y)
};
/* Reset container's x/y utility property */
container.moveposition = {x:event.pointerX(), y:event.pointerY()};
/* Border adds to dimensions */
var borderStyle = container.getStyle('border-width');
var borderSize = borderStyle.split(' ')[0].replace(/[^0-9]/g,'');
/* Padding adds to dimensions */
var paddingStyle = container.getStyle('padding');
var paddingSize = paddingStyle.split(' ')[0].replace(/[^0-9]/g,'');
/* Add things up that change dimensions */
var sizeAdjust = (borderSize*2) + (paddingSize*2);
/* Update container's size */
var size = container.getDimensions();
container.setStyle({
height: size.height+moved.y-sizeAdjust+'px',
width:size.width+moved.x-sizeAdjust+'px'
});
}
/* Listen for 'mouse down' on handle to start the move listener */
handle.observe('mousedown', function(event) {
/* Set starting x/y */
container.moveposition = {x:event.pointerX(),y:event.pointerY()};
/* Start listening for mouse move on body */
Event.observe(document.body,'mousemove',moveListener);
});
/* Listen for 'mouse up' to cancel 'move' listener */
Event.observe(document.body,'mouseup', function(event) {
Event.stopObserving(document.body,'mousemove',moveListener);
});
}
DragCorner('SomeDiv','DragHandle');
DragCorner('DivTwo','DragHandleTwo');
</script>

$("any_selector").resizable();
There are tons of other customizations available, but the basics are nice and simple. Just thought I'd throw it out there.
Thank you so much.
Great job! Just a note, I tried to use this, having the css definitions from an external stylesheet instead of inline, and it didn't work. Prototype couldn't get the border-width and padding values with getStyle(). To solve that, I used all the most specific attribute names: border-left-width, border-top-width, etc. and then I calculated the average of the 4 borders. Here is the changed piece of code:
var borderTopWidth = container.getStyle('border-top-width');
var borderBottomWidth = container.getStyle('border-bottom-width');
var borderLeftWidth = container.getStyle('border-left-width');
var borderRightWidth = container.getStyle('border-right-width');
var borderStyleAverage = (borderTopWidth + borderBottomWidth + borderLeftWidth + borderRightWidth) / 4;
var borderSize = borderStyleAverage.split(' ')[0].replace(/[^0-9]/g,'');
It seems to be a prototype issue, because it works for inline css and not for external stylesheets, although I saw some guys saying that it's a DOM issue, since prototype docs say "Not all CSS shorthand properties are supported. You may only use the CSS properties described in the Document Object Model (DOM) Level 2 Style Specification." By the way, we can do the same for the padding, using padding-left, padding-right, etc.
function DragCorner(container, handle) {
var container = $(container);
var handle = $(handle);
container.moveposition = { x: 0, y: 0 };
function moveListener(event) {
var moved = {
x: (event.pointerX() - container.moveposition.x),
y: (event.pointerY() - container.moveposition.y)
};
container.moveposition = { x: event.pointerX(), y: event.pointerY() };
function extractNumber(text) {
return +text.split(' ')[0].replace(/[^0-9]/g,'');
}
var borderTop = extractNumber(container.getStyle('border-top-width'));
var borderBottom = extractNumber(container.getStyle('border-bottom-width'));
var borderLeft = extractNumber(container.getStyle('border-left-width'));
var borderRight = extractNumber(container.getStyle('border-right-width'));
var paddingTop = extractNumber(container.getStyle('padding-top'));
var paddingBottom = extractNumber(container.getStyle('padding-bottom'));
var paddingLeft = extractNumber(container.getStyle('padding-left'));
var paddingRight = extractNumber(container.getStyle('padding-right'));
var heightAdjust = borderTop + borderBottom + paddingTop + paddingBottom;
var widthAdjust = borderLeft + borderRight + paddingLeft + paddingRight;
var size = container.getDimensions();
container.setStyle({
height: size.height + moved.y - heightAdjust + 'px',
width: size.width + moved.x - widthAdjust + 'px'
});
}
handle.observe('mousedown', function(event) {
container.moveposition = {x:event.pointerX(),y:event.pointerY()};
Event.observe(document.body,'mousemove',moveListener);
});
Event.observe(document.body,'mouseup', function(event) {
Event.stopObserving(document.body,'mousemove',moveListener);
});
}
document.observe('dom:loaded', function() {
DragCorner('dragBox', 'dragBoxCorner');
});
Thanks for the update on this. When I actually went to use it at work, I ran in the the exact issue you are describing. I ended up cheating and creating a version where you told it how much it need to compensate on with/height. I will look at updating it to use this code.
Happy Coding,
cfchris