I have in iframe table trs which draggable and droppable(jquery). Its work in chrome and ie normally, but when I want to drag and drop in FF, i must do 2 clicks to change trs.
$(this).draggable({ helper: 'clone', iframeFix: true, cursor: "move", cursorAt: { top: 600, left: 155 } });
$(childrensDraggableZone).droppable({
accept: '.dragdrop',
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
drop: function(event, ui) {
var draggable = ui.draggable, droppable = $(this),
dragPos = draggable.position(), dropPos = droppable.position();
draggable.css({
left: dropPos.left + 'px',
top: dropPos.top + 'px'
});
droppable.css({
left: dragPos.left + 'px',
top: dragPos.top + 'px'
});
draggable.swap(droppable);
}
});
Related
I'm facing a trouble with droppable/draggable plugin of Jquery UI.
If I have two elements, not-nested, but overlapped due to css structure, the drop function is thrown for both elements.
How can I prevent to the background element to get the drop?
This is an example:
https://jsfiddle.net/vq4x0b8L/2/
HTML
<div id="contenitore">
<div id="carrello">
<p>Drop here</p>
</div>
<div id="carrello2">
<p>Drop here</p>
</div>
<div id="fagioli">
<p>Drag me</p>
</div>
</div>
JS
$(function() {
$( "#fagioli" ).draggable();
$( "#carrello" ).droppable({
greedy: true,
drop: function( event, ui ) {
$( this )
.find( "p" )
.html( "Dropped." );
}
});
$( "#carrello2" ).droppable({
greedy: true,
drop: function( event, ui ) {
$( this )
.find( "p" )
.html( "Dropped." );
}
});
});
CSS
#contenitore {position: relative; width: 500px; height: 500px;}
#carrello {background: #ccc;width:400px;height:500px;}
#carrello2 {background: #ddd; width:300px;height:250px; position: absolute; bottom: 0px;}
#fagioli {background: #822222;width:70px;height:90px;position: absolute; top: 200px; right: 10px;}
#fagioli:hover {cursor:move}
I tried the "greedy" option, but it doesn't work, probably it is designed for nested elements.
I found a way to do it.
Example: https://jsfiddle.net/Twisty/dezt5bmf/10/
JavaScript
$(function() {
$("#fagioli").draggable();
$("#carrello").droppable({
drop: function(event, ui) {
console.log("Dropped on " + $(this).attr("id"));
$(this)
.find("p")
.html("Dropped.");
}
});
$("#carrello2").droppable({
tolerance: "touch",
drop: function(event, ui) {
console.log("Dropped on " + $(this).attr("id"));
$(this)
.find("p")
.html("Dropped.");
$("#carrello").droppable("option", "accept", "*");
},
over: function(event, ui) {
$("#carrello").droppable("option", "accept", ".snowflake");
}
});
});
When the Draggable is Over the 2nd droppable, we adjust the accept option to something that is not the draggable element. This way when drop happens, it is not interested in it. Once the dropped is performed, we can switch it back to accept all items.
You can also disable the dropables, yet this causes additional Styles to be applied. Changing the accept does not.
I have a 2x2 grid of droppable areas [[A,B][C,D]] and under the grid is a 1x4 grid of draggables. I only want certain draggables next to each other. So for example, if there is a draggable in B, and I drag a different draggable into A, is there a way to make the draggable in B revert? The draggables have data-row and data-col so that I can grab the draggable in the prev/next column if I need to.
$(".draggable").draggable({
scroll: false,
snap: ".snaptarget",
snapMode: "inner",
stack: ".draggable",
revert: function (event, ui) {
var $draggable = $(this);
$draggable.data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
return !event;
}
});
$(".snaptarget").droppable({
accept: ".draggable",
drop: function (event, ui) {
var $draggable = $(ui.draggable);
var $droppable = $(this);
// This droppable is taken, so don't allow other draggables
$droppable.droppable('option', 'accept', ui.draggable);
ui.draggable.position({
my: "center",
at: "center",
of: $droppable,
using: function (pos) {
$draggable.animate(pos, "fast", "linear");
}
});
// Disable prev or next droppable if the pagewidth == 1
if ($droppable.data("col") == 1) {
$droppable.next().droppable("option", "disabled", true);
var nextDrag = $(".draggable[data-row='" + $droppable.data("row") + "'][data-col='2']");
if (nextDrag.length) {
// I need to revert nextDrag if there is one.
// I've tried this but it doesn't seem to work
nextDrag.data("uiDraggable").originalPosition = {
top: 0,
left: 0
}
}
}
},
tolerance: "pointer"
});
Took a little bit of work, I am never good with offsets and positioning. Here's the key:
function returnItem(item, target) {
// Get Origin
var oPos = item.data("uiDraggable").originalPosition;
// Adjust Postion using animation
item.position({
my: "top left",
at: "top left+" + oPos.left,
of: target,
using: function(pos) {
item.animate(pos, "fast", "linear");
}
});
}
Here is a working example based on the Draggable Snap to element grid example:
https://jsfiddle.net/Twisty/a4ucb6y3/6/
HTML
<div id="target">
<div class="snaptarget ui-widget-header" data-col="1" data-row="1" style="top: 0; left: 0;">
</div>
<div class="snaptarget ui-widget-header" data-col="2" data-row="1" style="top: 0; left: 80px;">
</div>
<div class="snaptarget ui-widget-header" data-col="1" data-row="2" style="top: 80px; left: 0;">
</div>
<div class="snaptarget ui-widget-header" data-col="2" data-row="2" style="top: 80px; left: 80px;">
</div>
</div>
<br style="clear:both">
<div id="source">
<div id="drag-A" class="draggable ui-widget-content" style="left: 0;">
<p>Drag A</p>
</div>
<div id="draggable2" class="draggable ui-widget-content" style="left: 80px;">
<p>Drag B</p>
</div>
<div id="draggable3" class="draggable ui-widget-content" style="left: 160px;">
<p>Drag C</p>
</div>
<div id="draggable4" class="draggable ui-widget-content" style="left: 240px;">
<p>Drag D</p>
</div>
</div>
CSS
.draggable {
width: 80px;
height: 80px;
font-size: .9em;
position: absolute;
top: 0;
}
.draggable p {
text-align: center;
height: 1em;
margin-top: 30px;
}
#source {
width: 320px;
height: 80px;
position: relative;
}
#target {
width: 160px;
height: 160px;
position: relative
}
.snaptarget {
width: 80px;
height: 80px;
position: absolute;
}
jQuery
$(function() {
function returnItem(item, target) {
// Get Origin
var oPos = item.data("uiDraggable").originalPosition;
// Adjust Postion using animation
di.position({
my: "top left",
at: "top left+" + oPos.left,
of: target,
using: function(pos) {
item.animate(pos, "fast", "linear");
}
});
}
$(".draggable").draggable({
scroll: false,
snap: ".snaptarget",
snapMode: "inner",
stack: ".draggable",
revert: "invalid",
start: function(e, ui) {
var off = $("#source").position();
ui.helper.data("uiDraggable").originalPosition = {
top: ui.position.top,
left: ui.position.left
};
}
});
$(".snaptarget").droppable({
accept: ".draggable",
drop: function(event, ui) {
var $draggable = $(ui.draggable);
var $droppable = $(this);
// This droppable is taken, so don't allow other draggables
$droppable.droppable('option', 'accept', ui.draggable);
// Disable prev or next droppable if the pagewidth == 1
if ($droppable.data("col") == 1) {
$droppable.next().droppable("option", "disabled", true);
var nextDrag = $(".draggable[data-row='" + $droppable.data("row") + "'][data-col='2']");
if (nextDrag.length) {
// I need to revert nextDrag if there is one.
returnItem(nextDrag, $("#source"));
}
}
},
tolerance: "pointer"
});
});
In draggable, when we start to drag, we want to record the original position (in case we need to later revert). The revert option is set to invalid in case the user drags it off some other place weird.
We add the position to data of the dragged item so that it can be read later.
When that item is dropped is when the magic happens. You had done all the checking, just needed to return the item if it didn't fit. if nextDrag exists, we return it to it's source.
Going forward, you may want to consider appending, cloning, and removing the elements in the start/stop events. As it is now, we're really only adjust the positioning of the elements, not their hierarchy in the DOM. Depending on what your needs are, this may not matter.
I am creating a JQuery UI popup this way:
function ShowJQueryStandardDialog(searchTarget, title, width, height, closeFunction)
{
var $dialog = $('<div id="dialogDIV"><iframe id="dialogIFrame" frameborder="no" scrolling="auto" src="' + searchTarget + '" width="' + (width - 50) + 'px" height="' + (height - 50) + 'px"></iframe></div>');
$dialog.dialog(
{
modal: true,
title: title,
show: 'slide',
width: width,
height: height,
closeOnEscape: true,
close: function (event, ui)
{
if (typeof closeFunction === 'function') closeFunction();
}
});
}
I then want to get the instance of the popup elsewhere in the code so I can close it. I tried:
var $dialog = $('#dialogDIV');
var $dialog = $('.ui-dialog');
var $dialog = $('.ui-dialog-content');
But it returns empty object. Note that if I put the above code in the close method of the dialog, it works fine. Shall I conclude that I can't access the popup from outside its init code?
Found a way:
function ShowJQueryStandardDialog(searchTarget, title, width, height, closeFunction)
{
$dialog = $('<div id="dialogDIV"><iframe id="dialogIFrame" frameborder="no" scrolling="auto" src="' + searchTarget + '" width="' + (width - 50) + 'px" height="' + (height - 50) + 'px"></iframe></div>');
$dialog.dialog(
{
modal: true,
title: title,
show: 'slide',
width: width,
height: height,
closeOnEscape: true,
close: function (event, ui)
{
if (typeof closeFunction === 'function') closeFunction();
}
});
/* IMPORTANT BIT */
$(document).bind('close-dialog', function ()
{
$dialog.dialog('close');
});
}
Then call parent.$(parent.document).trigger('close-dialog'); when you want to close your dialog.
i'm using jquery hashchange technique for dynamically and smoothly(fadein) loading the contents in a website.Though it's dynamic the url gets changed in the addressbar which looks as follows..as you can see a pound symbol appears before filename.
www.whatever.com/#about.html
www.whatever.com/#contact.html and so on.
In my index page a div named 'folder1' is hidden by default and it's made visible 5seconds after the page is loaded and there is div folder2(check the code).
When you type url 'www.whatever.com' everything works as it should. But when you hit 'home' link it appends # to index.html so url will be whatever.com/#index.html.
And this time div 'folder2' show up right after page is loaded which should be hidden as per the code. I noticed css of those divs gets messed up this time.
I don't understand what's happpening there. Any help?
(function($,i,b){var j,k=$.event.special,c="location",d="hashchange",l="href",f=$.browser,g=document.documentMode,h=f.msie&&(g===b||g<8),e="on"+d in i&&!h;function a(m){m=m||i[c][l];return m.replace(/^[^#]*#?(.*)$/,"$1")}$[d+"Delay"]=100;k[d]=$.extend(k[d],{setup:function(){if(e){return false}$(j.start)},teardown:function(){if(e){return false}$(j.stop)}});j=(function(){var m={},r,n,o,q;function p(){o=q=function(s){return s};if(h){n=$('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this);
$(function() {
var newHash = "",
$mainContent = $("#main-content"),
$pageWrap = $("#page-wrap"),
baseHeight = 0,
$el;
$pageWrap.height($pageWrap.height());
baseHeight = $pageWrap.height() - $mainContent.height();
$("nav").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
$mainContent
.find("#guts")
.fadeOut(200, function() {
$mainContent.hide().load(newHash + " #guts", function() {
$mainContent.fadeIn(200, function() {
$pageWrap.animate({
height: baseHeight + $mainContent.height() + "px"
});
});
$("nav a").removeClass("current");
$("nav a[href="+newHash+"]").addClass("current");
});
});
};
});
$(window).trigger('hashchange');
});
above makes the entire jquery code.
this is the css.infact there are two divs.
#folder1{
float: left;
height: 100px;
width: 100px;
position: absolute;
top: 15px;
right: 100px;
display: none;
}
#folder2{
float: left;
height: 100px;
width: 100px;
position: absolute;
top: 15px;
right: 100px;
display: show;
}
below is the code usedto hide and show divs.
$(document).ready(function() {
$("#folder2").hide();
setTimeout(function(){
$("#folder1").show();
}, 5000);
setTimeout(function(){
$("#folder1").hide();
}, 10000);
setTimeout(function(){
$("#folder2").show();
}, 15000);
});
I am using this http://jqueryui.com/demos/droppable/
But I have a problem dragging to a droppable that is smaller than the draggable.
It will not drop on the droppable, but on the top left of the droppable.
(source: yart.com.au)
Is there any way around this?
Here is the code, thanks.
$('.draggable').draggable({
revert: 'invalid',
revertDuration: 500,
appendTo: 'body',
helper: function(event, ui) {
return $(this).clone().appendTo('body').css('zIndex', 5).show();
},
drag: function(event, ui) {
$(ui.helper).removeClass("enlarge");
$(ui.helper).addClass("thumbnail");
$(this).hide();
},
stop: function(event, ui) {
$(this).show();
//$(this).addClass("enlarge");
if ($(this).parent().hasClass("imageContainer")) {
$(this).addClass("thumbnail");
}
else {
$(this).addClass("enlarge");
}
},
//cursorAt: { top: 30, left: 40 },
delay: 100,
refreshPositions: true
});
$('.imageContainer').droppable({
accept: '.draggable',
drop: function(event, ui) {
ui.draggable.css({
"position": "relative",
"left": "0px",
"top": "0px"
});
if ($(this).children().length == 0) {
// ui.draggable.addClass("thumbnail");
$(ui.draggable).appendTo(this);
$(this).removeClass("border");
}
},
over: function(event, ui) {
ui.draggable.removeClass("enlarge");
ui.draggable.addClass("thumbnail");
$(this).addClass("border");
},
out: function(event, ui) {
// ui.draggable.removeClass("zoomIn")
$(this).removeClass("border");
},
tolerance: 'intersect'
});
CSS:
.thumbnail {
height:60px;
margin-right:10px;
width:80px;
z-index:1;
}
.enlarge {
border:5px solid white;
height:145px;
width:195px;
}
$('.draggable').draggable({
revert: 'invalid',
revertDuration: 500,
appendTo: 'body',
helper: function(event, ui) {
return $(this).clone().appendTo('body').css('zIndex', 5).show();
},
drag: function(event, ui) {
/* $(ui.helper).removeClass("enlarge");
$(ui.helper).addClass("thumbnail"); */
$(this).hide();
},
stop: function(event, ui) {
$(this).show();
//$(this).addClass("enlarge");
if ($(this).parent().hasClass("imageContainer")) {
$(this).addClass("thumbnail");
}
else {
$(this).addClass("enlarge");
}
},
//cursorAt: { top: 30, left: 40 },
delay: 100,
refreshPositions: true
});
Try replacing your code with this block above and see if it comes close to what you want. It may not be perfect yet, but let's see if we can tackle one change at a time. What I'm hoping to observe is that it drops approximately like it should.