Draggable is not working when parent gets hidden - jquery-ui

The following error just occurs in IE8.
Demo: http://tinyw.in/BLrg
Click on show at Newsletter 313. If you now hover over the blue bar at the left, a layer slides out containing some elements. You can drag each one of this elements. If you start dragging the layer slides back. As you see, in IE8, the dragged element also gets hidden or if you directly drag it over it might get added instantly. And that's the problem, you can open it in IE9, Firefox, Chrome and it works. To see, how it should actually work.
Here's the code which can be found in logic.frontend.js:
(Just a part which is actually used)
$( ".draggable li table" ).draggable({
connectToSortable: ".sortable",
helper: 'clone',
revert: 'invalid',
appendTo: 'body',
start: function(ui) {
$('#elementsContainer').hide('slide', {
direction: "left"
}, 500);
}
});
var height = $('#elementsContainer').outerHeight();
$('#elementsContainerHandle').css('height', height);
$('#elementsContainerHandle').mouseenter(function() {
$('#elementsContainer').css('visibility', 'visible');
$('#elementsContainer').show('slide', { direction: "left" }, 500);
});
$('#elementsContainer').mouseenter(function() {
$(this).css('visibility', 'visible');
});
$('#elementsContainer').mouseleave(function() {
$(this).css('visibility', 'hidden');
});
The problem is, that #elementsContainer gets hidden and due to that all it's children including the dragged element are getting hidden as well. In other browser, .hide() doesn't affect the dragged element because of the option appendTo : 'body'. But in IE8, this seems to break somehow although I'm quite sure the element gets added to the body. I've tried making the draggable visible again with css, .show() etc. but i didn't get it.
Thanks

Related

JQueryUI - droppable.touch change

I am currently trying to make an extended droppable area but I got some problem. Here is the code (explanation below) :
$('div#1').find('div[cid="draggable"]').each(function(i, e) {
$(e).after("<div id='drp' style='width:100%;'></div>");
$('div#drp').droppable({
drop:function(event, ui) {
ajaxCall = false;
ui.draggable.css("left", "0");
ui.draggable.css("top", "0");
$(event.target).after(ui.draggable);
$(this).css("height", "0px");
$(this).removeClass("isDroppable");
$(this).removeClass("mb-1");
var t = ui.draggable.attr("i");
// callPage(81758758, 'POST', {t:t,s:0}, '');
},
over:function(event, ui) {
$(this).css("height", (parseInt(ui.helper.css("height")) + 50)+"px");
$(this).addClass("isDroppable");
$(this).addClass("mb-1");
if($(this).prev().attr("o") < ui.helper.attr("o")) {
// Move to top : Un padding s'ajoute, étrangement.
}
},
out:function(event, ui) {
$(this).css("height", "0px");
$(this).removeClass("isDroppable");
$(this).removeClass("mb-1");
},
accept:function(d) {
if(d.attr("cid") == "draggable" && d.attr("i") != $(this).prev().attr("i")) {
return true;
}
},
tolerance:'touch'
});
});
So actually, I am creating, for each child of div#0, a div#drp. It means that if I have, in div#0, 5 div#card, I will have, for each div#card, a div#drp (width:100%, height:0), for a total amount of 5 div#drp. As you should have understand, each div#drp is a DROPPABLE AREA (and each div#card can be dropped on each div#drp).
But here is the problem : The only way to get this working is to set the tolerance, as it is on my code, to "touch", as long as "pointer", "intersect" & "fit" will never work because of div#drp is set to height=0px.
Now, imagine the following structure :
<div id="card" i="1" style="width:100%;height:300px;">CARDTEST</div>
<div id="grp" i="1" style="width:100%;height:0;"></div>
<div id="card" i="2" style="width:100%;height:100px;">CARDTEST</div>
<div id="grp" i="2" style="width:100%;height:0;"></div>
<div id="card" i="3" style="width:100%;height:100px;">CARDTEST</div>
<div id="grp" i="3" style="width:100%;height:0;"></div>
Here, if I move the 2nd or 3rd card, everything will be alright. But if I move the first card (with height:300px) :
First, the id#grp height will be set to "(parseInt(ui.helper.css("height")) + 50)+"px"", it means 350px.
Second, even with that, my first card will trigger the first div#drp and the second div#drp as long as it height is too big. It's like if changing the height of my div#drp doesn't extend my DROPPABLE AREA.
So, my question is : Is there a way to "actualise" the DROPPABLE AREA within the "over" event ? I tried to change the droppable event within the "over" event, I also tried to change the tolerance within the "over" event, but nothing seems to work.
Any idea ?
Solution :
There isn't anything in Droppable() making this possible. However, it is possible to update DROPPABLE AREA positions within Draggable options. See below :
$( ".selector" ).draggable({
refreshPositions: true
});
I didn't expect a DROPPABLE property to be editable through DRAGGABLE elements. Note that, according to the documentation :
"If set to true, all droppable positions are calculated on every mousemove. Caution: This solves issues on highly dynamic pages, but dramatically decreases performance."
Tested on multiples devices, it doesn't cause lags or freez, so it should be fine.
Note that this config value will also fix margins caused by any Element added on Droppable.over if the Draggable Element is under the Droppable element (In example, if you want to do the same as what Sortable() do, but with Draggable() & Droppable()).
Problem solved !

jQueryUI Accordion - Header Text and Slide

I'm playing around with jQueryUI Accordion for the first time and I'm trying to make simple expanding div, which switches it's header text and sliding to the bottom of the content, when expanded.
I have the default h3 header saying 'More' and I want it to change to 'Less', when the div is expanded and revert to 'More', when it is closed. Also, the header should slide down and stay below the content, when expanded.
I've been searching for 2 days with no luck.
Change text by #Irvin Dominin aka Edward
$(function() {
$( "#accordion" ).accordion({
header: 'h3',
collapsible: true,
active: false,
activate: function (event, ui) {
ui.newHeader.find(".accordion-header").text("Less")
ui.oldHeader.find(".accordion-header").text("More")
}
});
Slide Header by #vitaliy zadorozhnyy
var headers = $('#accordion h3');
headers.click(function () {
var panel = $(this).prev();
var isOpen = panel.is(':visible');
$(this).text(!isOpen ? 'Less' : 'More');
panel[isOpen ? 'slideUp' : 'slideDown']();
return false;
});
Now the problem is these two can't be used together. Any idea how to mix them?
You can use activate event to switch your accordion header text:
Triggered after a panel has been activated (after animation
completes). If the accordion was previously collapsed, ui.oldHeader
and ui.oldPanel will be empty jQuery objects. If the accordion is
collapsing, ui.newHeader and ui.newPanel will be empty jQuery objects.
Code:
$('#accordion').accordion({
activate: function (event, ui) {
ui.newHeader.find(".accordion-header").text("Less")
ui.oldHeader.find(".accordion-header").text("More")
}
});
Demo: http://jsfiddle.net/IrvinDominin/r93wn/
if you use accordion with one item and want to slide it when it is active then use collapsible option
In your case $('#accordion').accordion({collapsible:true});
but if u want to slide header down you can use another approach. I have made some sample on JsFiddle for you.
Hope it helps.

jquery dialog - push the background content down

I'm having a strange problem with the jquery dialog popup that I'm hoping someone here can help. The pop up codes looks like below. It works fine except for one thing. When the pop-up is displayed, it will sometimes push the background content down by about the height of the the dialog window. Is there a way to prevent this from happenning?
$("#searchPopUp").dialog({
modal: true,
bgiframe: false,
autoOpen: false,
resizable: true,
position:{ my: "center", at: "center", of: window },
title: 'Choose one search criteria and<br/>populate the corresponding field below:',
width: 400,
close: function( event, ui ) {},
buttons: {
"Search": function() {
$("#viewDevicesSearchForm\\:searchCommandLink").click();
},
"Close": function() {
$( this ).dialog( "close" );
}
}
});
This is because jquery sets position to relative, and then moves the popup to the right place using top and left. I found two ways to fix the problem:
1) The easier of the two: set margin-bottom of the dialog container to negative its height.
popup.dialog({
...other options...,
open : function() {
popup.css('margin-bottom', 0 - popup.height());
},
});
2) For the dialog container, set the position to absolute and adjust the top and left. To put it in the right place, add the offset position of where it is getting placed to the top value that jquery set. The calculation is similar for left.This should do it, but different parameters to the dialog may require different calculations.

Issue with JQuery UI 'Droppable'

This is the problem I am having:
I have created several draggable elements but when I drop one on the droppable element, it does not stay there.
Below are more details.
My JavaScript function receives JSON array from PHP and then uses a loop to create the draggable elements:
<script type="text/javascript">
function init() {
var items = <?php echo $result_j;?>; //items is an one dimensional array
for ( var i=0; i<<?php echo $total_rows_j;?>; i++ ) {
$('<div>' + items[i] + '</div>').data( 'item_name', items[i] ).attr( 'class', 'snk_button' ).appendTo( '#drag' );
}
With the 'items' array I have created several div elements (above code) which I then turn into draggable elements (code below).
$(".snk_button").draggable( {
containment: '#drag_section',//Div #drag_section contains the Div #drag
stack: '#drag div',
cursor: 'move',
revert: true
} )
So, far everything seems to be as expected and I am able to drag my elements (created from 'items' array).
Next, I have created the droppable element as shown below:
$( "#dropp" ).droppable({
drop: function() {
alert('ok');
}
});
}// End function init()
</script>
But when I drag one of my draggable elements on this droppable element, I even get the alert, but the draggable element does not stay on the droppable element.
Can anyone please help me identify why my draggable element is not staying on the droppable element?
Thanks in advance for any help!
You have used revert :true.. It means
Revert means If set to true, the element will return to its start position when dragging stops. Possible string values: 'valid', 'invalid'. If set to invalid, revert will only occur if the draggable has not been dropped on a droppable. For valid, it's the other way around.
Probably you need invalid in case your draggable element is not dropped on proper element
Thanks very much for pointing me in the right direction.
I have solved this particular problem in the following way:
I have edited my droppable code as below:
$( "#filtered" ).droppable(
drop: handleDrop
});
function handleDrop( event, ui ) {
ui.draggable.draggable( 'option', 'revert', false );
} // End function handleDrop
This has solved the problem of the draggable not staying on the droppable (that was previously described).

jQuery UI droppable: resizing element on hover not working

I have a jQuery UI droppable element which I would like to get bigger when a draggable is hovered over it. I have tried both using the hoverClass option and also binding to the drophover event.
Visually, both these methods work fine. However, once the draggable exits the original (smaller) boundary of the droppable, jQuery UI interprets this as a 'dropout', despite still being within the current (larger) boundary.
For example, js:
$("#dropable").droppable({
hoverClass: 'hovering'
}.bind('dropout', function () {console.log('dropout')});
css:
#droppable { background: teal; height: 10px; }
#droppable.hovering { height: 200px; }
In this case, when a draggable hovers over the droppable, the droppable visually increases in size to 200px. If at this point, the draggable is moved down by 20px, I would expect it to still be hovering over the droppable. Instead, jQuery UI fires the dropout event and the droppable reverts to being 10px high.
Anyone know how to get it to behave in the way I'd expect it to?
jsFiddle example: http://jsfiddle.net/kWFb9/
Had the same problem, I was able to solve it by using the following options:
$("#droppable").droppable({
hoverClass: 'hovering',
tolerance: 'pointer'
});
$('#draggable').draggable({
refreshPositions: true
});
Here's the working fiddle: http://jsfiddle.net/kWFb9/51/
See http://bugs.jqueryui.com/ticket/2970
So I made a couple tweaks to your fiddle
First I set the droppable tolerance to "touch" which will activate whenever any part of the draggable is touching it. This causes the hovering class to be applied.
Next I added an animation to resize your draggable element slightly. I wasn't sure if this was functionality you wanted or not so I put it in there anyways.
Lastly, I permanently apply the hovering class to the droppable element when the draggable element is dropped into the droppable zone. This way the droppable doesn't revert to that narrow height when there is an element in it
http://jsfiddle.net/kWFb9/2/
EDIT:
Better fiddle: http://jsfiddle.net/kWFb9/6/
I hope this helps :)
you could create a bigger (i.e. the size of #droppable.hovering) div without background and apply your droppable to it. Note that you didn't provide HTML but the new #drop_container should contain both divs.
JS
var dropped;
$("#droppable").droppable({
drop: function(event, ui) {
dropped = true;
}
});
$('#draggable').draggable({
start: function(event, ui) {
$("#droppable").addClass("hovering");
dropped = false;
},
stop: function(event, ui) {
if (!dropped) {
$("#droppable").removeClass("hovering");
}
}
});
CSS
#droppable { background: teal; height: 10px; }
#droppable.hovering, #drop_container { height: 200px; }
Or you could try another solution with .live() or .livequery() from this article
[EDIT] I've edited my code and here is a jsfiddle: http://jsfiddle.net/94Qyc/1/
I had to use a global var, I didn't find a better way to check wether the box was dropped. If anybody has an idea, that would be great.
There is an other (hum hum) not bad solution :
TL;DR: Fiddle
The problem is that the plugin stores dom element's size values when the widget is created (something like) :
//jquery.ui.dropable.js
$.widget("ui.droppable", {
...
_create: function() {
var proportions,
this.proportions = function() { return proportions; }
And the offset for widgets are initialized in $.ui.ddmanager.prepareOffsets();
So we only need to overwrite the proportions object.
This way allow to access to real plugin properties so we can write something like :
$("#droppable").droppable({
hoverClass: 'hovering',
over: function(ev, ui) {
var $widget = $(this).data('droppable');
$widget.proportions = {
width: $(this).width(),
height: $(this).height()
};
},
out: function(ev, ui) {
var $widget = $(this).data('droppable'); //ui-droppable for latests versions
$widget.proportions = {
width: $(this).width(),
height: $(this).height()
};
}
})

Resources