I'm working on my first JQuery project, and i've hit a bit of a roadblock. I'm trying to allow drag & drop reordering of a set of nested lists (ul). Everything is working with the exception of the positioning. The goal is to vertically center the draggable relative to the cursor (horizontal movement is restricted), so that an li with elements nested inside it can be easily dropped. Here's the relevant JS:
$(function() {
$( ".organizerlink" ).draggable({ axis: "y",
containment:"#organizer",
scroll: false ,
helper: "original",
revert: "invalid",
cursorAt: { top: Math.round($(this).outerHeight() / 2)}
});
and HTML:
<ul id="organizer">
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-1">Page
<ul><li class="organizerTarget organizerNewParent"> </li></ul>
</li>
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-2">About
<ul>
<li class='organizerTarget'> </li>
<li class='organizerlink' id="dbid-3">Another Page<ul><li class="organizerTarget organizerNewParent"> </li></ul></li>
<li class='organizerTarget'> </li>
<li class='organizerlink' id="dbid-4">Example<ul><li class="organizerTarget organizerNewParent"> </li></ul></li>
</ul>
</li>
<li class="organizerTarget"> </li>
<li class="organizerlink" id="dbid-27">Stuff
<ul><li class="organizerTarget organizerNewParent"> </li></ul>
</li>
Some stuff I've already tried:
setting cursorAt to $(this).height() - didn't work, i'm guessing height() pulls the css heights in, but they aren't defined explicitly so it jumps to 0
setting it to outerHeight() gives me an error "elem.style is undefined" in firebug
I know the outerHeight element exists in jquery, and based on the API doc it would appear that it can be calculated automatically, even if the CSS is undefined, so I'm thinking that is the right way to be going, and perhaps $(this) is just the wrong spot to be looking for it.
I also wanted to center my draggable objects after I pick them up. My solution:
$(".dragme").draggable({
start: function(event, ui) {
$(this).draggable("option", "cursorAt", {
left: Math.floor(this.clientWidth / 2),
top: Math.floor(this.clientHeight / 2)
});
}
});
Worked around the initial problem, see the comment to my initial post.
EDIT:
Tolerance option "pointer": The mouse pointer overlaps the other item.
$(".sortable").sortable({
containment: "parent",
tolerance: "pointer"
});
This works fine if draggable have helper object. Just put it in start method of draggable as below code.
start: function(event, ui) {
$(this).draggable("option", "cursorAt", {
left: Math.floor(ui.helper.width() / 2),
top: Math.floor(ui.helper.height() / 2)
});
}
I just spent a couple of hours smashing my head against the wall to try to reliably make this work, so I thought I'd post the solution :)
Issue:
Draggable cannot set cursorAt for 'clone' drags during instantiation for dynamic values (i.e. the center of a draggable proxy of variable size) because ui.helper hasn't been created yet! You can set it inside the start handler but it will not work for the first drag.
Solution:
Set the cursorAt inside start, but ALSO manually override the ui.position for the drag event, which occurs continuously. Using a firstRun boolean, you can prevent it from running needlessly. You must set the default cursorAt to the top left for repositioning.
Enjoy!
$jobs.each( function( index, element ) {
var $el = $(element),
firstRun = true;
/*
* jQuery UI Draggable
* See #link: http://api.jqueryui.com/draggable/
*
* Note that for clone drags, the first drag cannot center the proxy because ui.helper hasn't been created yet
* so need to set it manually for first drag. Subsequent drags can use the cursorAt property.
* See my #link:
*/
$el.draggable({
cursorAt : [0, 0], // Set origin then update dynamically
drag : function( evt, ui ) { // Fires after start event, and continuously during drag
if ( firstRun ) {
// Reset proxy position here since cursorAt cannot be set for
ui.position.left -= Math.floor( ui.helper.width()/ 2 );
ui.position.top -= Math.floor( ui.helper.height()/ 2 );
};
},
helper : 'clone',
start : function( evt, ui ) { // Fires once
if ( firstRun ) {
// Center proxy relative to cursor for future drags
$(this).draggable( 'option', 'cursorAt', {
left : Math.floor( ui.helper.width()/ 2 ),
top : Math.floor( ui.helper.height()/ 2 )
});
};
// Set cursor ( 'cursor' option just applies style to <body> )
ui.helper.css( 'cursor', 'move' );
},
stop : function( evt, ui ) { // Fires once
if ( firstRun ) {
firstRun = false;
};
}
});
In case of multiply draggable objects Goz's answer didn't work for me, so here is my solution without using cursorAt option
var offsetX = null;
var offsetY = null;
$(".item").draggable({
helper:"clone",
start:function(e,ui){
offsetX=null;
offsetY=null;
},
drag:function(e,ui){
if(offsetX===null){
offsetX = e.clientX-ui.offset.left;
offsetY = e.clientY-ui.offset.top;
}
ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );
}
});
.desk{
width:300px;
height:300px;
border:2px dashed gray;
}
.item {
padding:8px;
margin:2px;
border:1px solid blue;
background: rgba(0,0,80,.3);
display:inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<div class="desk">
<div class="item">Item 1</div>
<div class="item" style="width:100px;">Item 2</div>
<div class="item" style="height:50px;">Item 3</div>
</div>
#yuri gor:
Your answer worked for me, but you could have just inited the offset from start:
var offsetX = null;
var offsetY = null;
$(".item").draggable({
helper:"clone",
start:function(e,ui){
offsetX = e.clientX-ui.offset.left;
offsetY = e.clientY-ui.offset.top;
},
drag:function(e,ui){
ui.position.left += offsetX - Math.floor( ui.helper.outerWidth()/ 2 );
ui.position.top += offsetY - Math.floor( ui.helper.outerHeight()/ 2 );
}
});
Related
I am using JQuery Draggable function and Touch Punch to produce a list of horizontal sliders that can be scrolled by clicking and dragging. It works great in touch and click devices. The problem I am facing is that if I try to scroll up or down in touch devices, it doesn't work.
I have looked through SO and found that removing "event.preventDefault" from TouchPunch allows vertical scrolling, the problem with this fix is, that it only works on some devices, and not all.
I am wondering if anyone has any other solutions, or alternative way of producing the same horizontal sliders that work on both touch and click events.
Here is Example code (JQuery Draggable):
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$("#list1 ul").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
$("#list2 ul").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
});
#list1 {
position: relative;
height: 16em;
width: 100%;
text-align: middle;
white-space: nowrap;
overflow-x: hidden;
overflow-y: hidden;
}
#list1 .floating-box {
margin: auto;
display: inline-block;
width: 15em;
height: 13.5em;
margin: 0.1em;
border: 0.2em solid black;
background-color: white;
}
#list2 {
position: relative;
height: 16em;
width: 100%;
text-align: middle;
white-space: nowrap;
overflow-x: hidden;
overflow-y: hidden;
}
#lis2 .floating-box {
margin: auto;
display: inline-block;
width: 15em;
height: 13.5em;
margin: 0.1em;
border: 0.2em solid black;
background-color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="list1">
<ul>
<p>One</p>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
</ul>
</div>
<div id="list2">
<ul>
<p>Two</p>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
<div class="floating-box">Floating box</div>
</ul>
</div>
If I touch list1 or list2 div and try to scroll up or down, it doesn't recognize the movement. Any help or direction would be appreciated.
EDIT
Based on the idea to determine theswipe direction based on the pageY propertie of touchemove.
I think it's a good idea to avoid the annoying double tap (see first answer below) on the long run.
There is still a compromise on it, but it is much more reasonable.
I tried many things... The best result I got is when I gave up on simulating a scroll on touchmove.
So here is the way to I now use each of the three touch events:
touchstart gets the initial variables like: window scrollTop and pageY.
touchmove determines the swipe direction and gets the last pageY.
touchend does the math as to were the page should scrollTo.
For the cuteness, I've put that result value in an .animate().
I was pleasantly surprised to see that it compensates quite really smoothly the fact that the page scrolls only on touchend.
I think that very few users will notice it ;).
Since "Touch-Punch" is working by default for horizontal swipes, the "compromise" only affects the vertical scroll.
Here is the code:
And a live link to try it on a touche-enabled device.
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$(".draggable").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
var startTouchX=0;
var startTouchY=0;
var actualPosX;
var actualPosY;
var eventCounter=0;
var directionDetermined=false;
var direction;
var thisTouchX;
var thisTouchY;
var lastTouchY;
$(document).on("touchstart", function(e) {
// Actual document position
actualPosX = $(document).scrollLeft();
actualPosY = $(document).scrollTop();
// StartTouches
startTouchX = parseInt(e.originalEvent.touches[0].pageX);
startTouchY = parseInt(e.originalEvent.touches[0].pageY);
});
$(document).on("touchmove", function(e) {
// Arbitrary considering ONLY the fourth event...
// Touchmove fires way too many times!
// We only need to determine the main direction ONCE.
// This prevents an "s" swipe from messing this code.
eventCounter++;
if(eventCounter==4 && !directionDetermined){
thisTouchX = parseInt(e.originalEvent.touches[0].pageX);
thisTouchY = parseInt(e.originalEvent.touches[0].pageY);
if ( (Math.abs(thisTouchX - startTouchX)) / Math.abs(thisTouchY - startTouchY) > 1){ //check swipe direction
// HORIZONTAL
$("#debug").html("HORIZONTAL");
directionDetermined=true;
// NO NEED here. This is re-enabled on touchend, if it has been disabled.
//$(".draggable").draggable('enable');
}
else{
// VERTICAL
$("#debug").html("VERTICAL");
directionDetermined=true;
direction="vertical";
$(".draggable").draggable('disable'); // Disable draggable.
}
}
// Getting all the Y touches...
// The "last" value will be used on touchend.
lastTouchY = parseInt(e.originalEvent.touches[0].pageY);
//$("#debug").html(lastTouchY);
});
$(document).on("touchend", function(e) {
if(direction=="vertical"){
//$("#debug").html(lastTouchY);
var thisMoveY = -parseInt(lastTouchY - startTouchY);
//$("#debug").html(thisMoveY);
var newPosY = (actualPosY + thisMoveY);
//$("#debug").html(actualPosX+ " " +newPosY);
//window.scrollTo(actualPosX, newPosY);
$("html,body").animate({ scrollTop: newPosY },400);
}
// Reset everything for a future swipe.
startTouchX=0;
startTouchY=0;
eventCounter=0;
directionDetermined=false;
direction="";
$("#debug").html("");
// Re-enable draggable.
$(".draggable").draggable('enable');
});
});
First answer, using a "double-tap" to switch direction.
First, the Touch Punch website states that it's basically a jQuery-UI hack to handle some cases actually unhandled by jQuery-UI...
And that it is possible to find cases where Touch Punch fails.
Your issue was reported to the Touch Punch developpers here.
As an answer to that (in my words here), they said that it isn't really bug or an issue...
But a usage "conflict" on two different "wished" actions that are using the same touch events.
Sometimes to scroll the page, and sometimes to drag an element.
As a solution hint, they posted this Fiddle.
It suggests to find a way to disable draggable when needed.
But in this solution, the scrollable section is within the draggable element.
Which is not your case.
And you use almost all the mobile screen space for your draggable elements, so there is not enougth space left to trigger a draggable("disable") around them.
So... I had this idea, which I hope will help.
What if you'd find an elegant way to inform your users that a "double-tap" changes the movement orientation.
Here, I suggest a quite simple "double arrow" showing the movement direction.
Maybe you'll find something better.
This sure is a little compromise user experience, to ask them to double tap...
But if your layout really needs it, maybe it's ok.
So here, I reproduced your initial issue.
And here is the fix that I suggest.
I only tryed it on a Samsung Galaxy S3, but should work on every touch device.
$(function() {
var slides = $('#list1 ul').children().length;
var slideWidth = $('#list1').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$(".draggable").width(slides * slideWidth).draggable({
axis: 'x',
drag: function(event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
// Flag
var draggableEnabled=true;
// Find the doubletap position (to show a nice double arrow)
var tapPosition=[];
$(document).on("touchstart",function(e){
tapPosition[0] = parseInt(e.touches[0].pageX) - $(document).scrollLeft() - ($("#arrows img").width()/2);
tapPosition[1] = parseInt(e.touches[0].pageY) - $(document).scrollTop() - ($("#arrows img").width()/2);
});
Hammer(document).on("doubletap", function() {
//alert("Double tap");
draggableEnabled = !draggableEnabled; // Toggle
if(!draggableEnabled){
$(".draggable").draggable('disable'); // Disables draggable (and touch Punch)
$("#arrows img").css({
"transform":"rotate(90deg)", // Nice vertical double arrow
"top":tapPosition[1],
left:tapPosition[0]
}).fadeIn(600, function(){
$(this).fadeOut(600);
});
}else{
$(".draggable").draggable('enable'); // Enables draggable (and touch Punch)
$("#arrows img").css({
"transform":"rotate(0deg)", // Nice horizontal double arrow
"top":tapPosition[1],
left:tapPosition[0]
}).fadeIn(600, function(){
$(this).fadeOut(600);
});
}
});
});
Notice that it uses the Hammer.js (CDN) to detect the double tap.
And some extra CSS for the double arrow.
#arrows img{
width: 60vw;
height: 60vw;
position: fixed;
top:calc( 50vh - 60vw );
left:calc( 50vh - 60vw );
z-index:1000;
display:none;
}
This is the closest I have come to it, I wonder if someone could refine this code:
$(watchlist).on("touchstart", function(e) {
touchY = e.originalEvent.touches[0].pageY;
touchX = e.originalEvent.touches[0].pageX;
});
$(watchlist).on("touchmove", function(e) {
var fTouchY = e.originalEvent.touches[0].pageY;
var fTouchX = e.originalEvent.touches[0].pageX;
if ((Math.abs(fTouchX - touchX)) / Math.abs(fTouchY - touchY) > 1){ //check swipe direction
$("#watchlist ul").draggable( 'enable'); //if swipe is horizontal
}
else{
$("#watchlist ul").draggable( 'disable'); //if swipe is horizontal
}
});
The problem with this code is, that it deactivates the draggable function only after the touch move has been finished rather than during. If anyone could modify this code so that the draggable function is deactivated during as soon as the condition is met, during touchmove, rather than after, I would give them the bounty.
So i was working on rotating and dragging images for avatar pictures for my website, i estimated that it would take me 3 or 4 hours to add those functionalities to my website, and now it's been 3 days and i haven't been able to do anything with this bug: when an element is rotated (any degree except 0), whenever i try to drag it, the width and height of the dragged element are automatically set to the width and height of the parent, which fucks with the whole min/max-height and min/max-width process (this happens on 90 and 270 degree rotates, on a 180deg rotate, only the below bug exists).
another bug, whenever i actually drag it, everything is reversed, for example in a 180deg rotate, when i drag my image to the right the element goes to the left, without the 180deg rotate, everything would work fine.
so please someone give me a solution before i commit suicide.
and be careful, on dragging, i want my image to be contained within its parent, so nothing except the image is visible inside the parent (you get this, the html structure i used is because i am working on a profile picture), i added the #child because otherwise, whenever i applied the rotates to my image directly, it would go out of its parent and no transform-origin combinations would work with all the different image sizes and rotate angles, so i added the #child, which is an element with equal height and widths (so the element actually never goes out of its parent when rotating) and i applied my rotates to that element instead of the actual img, and i believe that you get the #parent, it is just a container, and if you are asking why i am not using containment: $("#parent") in my jquery, it is because that when i added this instead of the whole drag:function(){}, the dragging becomes jumpy instead of the smooth dragging effect i get using the current option (run a function on drag).
here's the fiddle and feel free to try different rotation degrees: https://jsfiddle.net/5kkwsLm8/
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js" type="text/javascript"></script>
<style>
</style>
</head>
<body>
<div id="parent" style="width:150px;height:150px;overflow:hidden;cursor:pointer;background-color:red;margin:0;padding:0;position:relative;">
<div id="child" style="width:100%;height:100%;transform:rotate(180deg)">
<img id="draggable" alt="Hello" src="mario.jpg" alt="mario" style="min-height:100%;max-height:100%;min-width:100%;">
</div>
</div>
<script>
$(document).ready(function(){
var y1 = $("#parent").height();
var x1 = $('#parent').width();
var y2 = $('#draggable').height();
var x2 = $('#draggable').width();
$( "#draggable" ).draggable({
drag: function(event, ui) {
if(ui.position.top >= 0) {
ui.position.top = 0;
}
else if(ui.position.top <= y1 - y2) {
ui.position.top = y1 - y2;
}
if(ui.position.left >= 0) {
ui.position.left = 0;
}
else if(ui.position.left <= x1 - x2) {
ui.position.left = x1 - x2;
}
},
stop: function(event, ui) {
}
});
})
</script>
</body>
</html>
I am working on a Javascript / html5 project for iPad.
I need to be able to catch touchmove events on an element that does not get added to the DOM until after a touchstart event has fired (i.e. until after a person has put their finger on the screen.)
I have tried simulating a touchstart event and firing it programatically...
$( "#container" ).append( element );
element.on( "touchmove", doStuff );
var ev = $.Event( "touchstart" );
element.trigger( ev );
...however this does not work. The only way I can get doStuff to start firing is to lift my finger and then touch the screen again, triggering a second touchstart event.
How can I catch touchmove events on an element that is added to the DOM after my finger is already on the screen?
To summarise, you appear to want :
on touchstart: to display and position a styled div element.
on touchmove: to drag the element without releasing and re-pressing the mouse button.
If this interpretation is correct, then the answer is to to handle touchmove events on the same element that was originally clicked on - namely the "body" element. It is not necessary to handle touchmove events of the element you want to drag (the added element).
There must be many ways to write the code. Here's one, which is probably not exactly what you want (chiefly in the positioning maths) but should be simple to adapt :
var $element = $("<div class='element' />");
$("body").on({
'touchstart mousedown': function (e) {
$element.appendTo("body");
$(this).on('touchmove mousemove', move);
move(e);//you could do `$(this).trigger('touchmove', e)` but a conventional function call keeps `move` simple.
},
'touchend mouseup': function (e) {
$(this).off('touchmove mousemove');
}
});
function move(e) {
$element.css({
left: (e.pageX - 10) + 'px',
top: (e.pageY - 10) + 'px',
cursor: 'pointer'
});
}
mousedown/mousemove/mouseup allow for desktop testing and can be removed for touch device usage.
DEMO
If you just need it to trigger once then it is quite easy
function addElement() {
$( "body" ).append( element );
element.on( "touchmove", doStuff );
element.trigger("touchmove");
}
http://jsfiddle.net/rx4qdtuj/8/
I checked this on my ipad simulator. I replaced the alert with append so you don't get constantly alerted on ipad.
If you want it to continually trigger, the only possible thing I can think of was to fake the touchmove on the created element
http://jsfiddle.net/rx4qdtuj/9/
var element = $("<div class='element' />");
$( "body" ).on( "touchstart", addElement );
$(".wrapper").on("touchmove", addElement);
function addElement() {
$( "body" ).append( element );
element.on( "touchmove", doStuff );
element.trigger("touchmove");
}
function doStuff() {
$('body').append('a ')
}
HTML
<div class="wrapper"></div>
CSS
.wrapper {
position: absolute;
top: 100px;
left: 100px;
width: 300px;
height: 300px;
}
The move actually triggers on the already created div wrapper which is in the same spot as the created element
see documentation draggable function
applicate you function
<div id="track" class="track">
<div id="box2" style="left:0; top:0">Drag Me</div>
</div>
native javascript
window.addEventListener('load', function(){
var box2 = document.getElementById('box2'),
boxleft, // left position of moving box
startx, // starting x coordinate of touch point
dist = 0, // distance traveled by touch point
touchobj = null // Touch object holder
box2.addEventListener('touchstart', function(e){
touchobj = e.changedTouches[0] // reference first touch point
boxleft = parseInt(box2.style.left) // get left position of box
startx = parseInt(touchobj.clientX) // get x coord of touch point
e.preventDefault() // prevent default click behavior
}, false)
box2.addEventListener('touchmove', function(e){
touchobj = e.changedTouches[0] // reference first touch point for this event
var dist = parseInt(touchobj.clientX) - startx // calculate dist traveled by touch point
// move box according to starting pos plus dist
// with lower limit 0 and upper limit 380 so it doesn't move outside track:
box2.style.left = ( (boxleft + dist > 380)? 380 : (boxleft + dist < 0)? 0 : boxleft + dist ) + 'px'
e.preventDefault()
}, false)
}, false)
I am experiencing an issue with the jQuery-UI draggable and droppable. The issue that I'm facing is the fact that:
When I move an element from one div to another (during dragging using
.append() ) it shifts the element away from the mouse cursor
jarringly.
I know what causes it the left / top css positions are no longer correct since I'm moving from one relative div to another. But a fix for it I can't find.
I have tried quite a few "solutions" :
Changing the cursorAt position http://api.jqueryui.com/draggable/#option-cursorAt while dragging but this only goes in affect after mouseup and on the next mousedown.
Changing the css during dragging: http://api.jqueryui.com/draggable/#event-drag which while it works is not ideal since it has hiccups that make it flicker and move in random directions which is highly annoying.
Making the draggable div absolute instead of relative (Which locally in my backbone application so far has the 'best' results but is still far from desirable since i require the elements in the sidebar to be relative so they append nicely one below the other )
Here is my JSBin example of my issue.
JavaScript
var positionStack = [];
var fieldview = $('#field');
var sidebarView = $('#sidebar');
$('.draggable').draggable({
containment: ".container",
zIndex: 100,
cursorAt: {
top: 20,
left: 25
},
snap: '.sidebar',
snapMode: 'inner'
});
$('#field').droppable({
over: function(event, ui) {
dragOverElement({event: event, ui:ui});
}
});
$('#sidebar').droppable({
over: function(event, ui) {
dragOverElement({event: event, ui:ui});
}
});
function dragOverElement(data){
var me = this;
var lastItem = positionStack[positionStack -1];
if(lastItem !== data.event.target.id)
{
positionStack.push(data.event.target.id);
var player = $(data.ui.draggable);
var target = data.event.target.id;
switch(target)
{
case ('field'):
fieldview.append(player);
player.css('position', 'absolute');
break;
case ('sidebar'):
sidebarview.append(player);
player.css('position', 'absolute');
break;
}
}
}
If I have markup like this:
<!-- Other Content -->
<div id="container">
<div class="draggable">
</div>
<div class="draggable">
</div>
</div>
<!-- Other Content -->
How can I have the container div expand vertically (I only want #container to be capable of expanding downward) as I drag one of the draggables? I've thought about using the drag callback, but there's gotta be a CSS way, right?
You can't do it with css, because div#container element didn't get any class triggered from draggables.
Best way is to do it with callback:
$('.draggable').draggable({
start: function(event, ui) { $('#container').addClass('expand'); },
stop: function(event, ui) { $('#container').removeClass('expand'); }
});
I have made some progress, but this is still not working the way I would like it to.
Here's how I now have it partially working (using the markup above):
var dragCatch = function(event, ui) {
var containerOffset = $('#container').offset().top;
var containerBottom = containerOffset + $('#container').height();
var componentHeight = $(this).height();
if (event.pageY > containerBottom - componentHeight - 2) {
$('#container').height(event.pageY - containerOffset + componentHeight + 2);
$(this).css('top', event.pageY - containerOffset);
}
};
$(this).each(function() {
$(this).draggable({
grid: [117,1]
,snap: '.draggable'
,snapMode: 'outer'
,containment: '#container'
,drag: dragCatch
})
});
This code will successfully resize the #container div, but will stop moving the .draggable div where #container used to end. If I let go, then drag again, then the .draggable will again move to where #container ends, then will stop even if #container continues to expand in size.
The conclusion that I have come to is that this may not even be possible. I went with an alternate method of using jQuery.resizable to do it manually instead.