Jquery drag n drop photo editor with clone on parent container - javascript

I am trying to implement a banner management system and was planning on using the jquery Photo Manager. The problem I am currently facing is that I cannot seem to get the parent image to clone on the primary container.
Here is the link to the fiddle for the codes (It is basically the same from the jQuery UI site)
What I am intending to create is to allow users to drag or add the image from the left to right and users can add the same image multiple times but as soon as the image is added to the right it disappears from the left.
I was looking at this piece of code for solution but do not see any removal of DOM elements specific to the item getting moved. only items removed from the DOM are the icons.
function deleteImage($item) {
$item.fadeOut(function () {
var $list = $("ul", $trash).length ? $("ul", $trash) : $("<ul class='gallery ui-helper-reset'/>").appendTo($trash);
$item.find("a.ui-icon-trash").remove();
$item.append(recycle_icon).appendTo($list).fadeIn(function () {
$item.animate({
width: "48px"
})
.find("img")
.animate({
height: "36px"
});
});
});
}
can someone help me out with an explanation.
Thanks in advance.

Actually using the jquery .clone() function did the trick. All I had to do was instead of passing the object of the element, I passed their clones with the events.
$trash.droppable({
accept: "#gallery > li",
activeClass: "ui-state-highlight",
drop: function (event, ui) {
deleteImage(ui.draggable.clone(true));
}
});
setting the parameter to true for the clone, makes a deep copy of the element including all the events.
$("ul.gallery > li").click(function (event) {
var $item = $(this),
$target = $(event.target);
if ($target.is("a.ui-icon-trash")) {
deleteImage($item.clone(true));
} else if ($target.is("a.ui-icon-zoomin")) {
viewLargerImage($target);
} else if ($target.is("a.ui-icon-refresh")) {
$item.remove();
}
return false;
});
Here is the link to the working fiddle for reference. Link

Related

Draggable drops in wrong place on second drag

I'm trying to drag "templates" (initially as clones) from a "store" into droppable slots. Thereafter I want to be able to drop the dragged item into whatever slot I wish. Draggables are set as follows:
$( ".template" ).draggable({
helper: "clone",
}
);
$( ".item" ).draggable();
I got round the issue of the thing re-cloning by replacing the "template" class with an "item" class on first drop and within the drop function switching from a clone to a straight element as follows:
$( ".template-slot" ).droppable({
accept: ".template, .item",
drop: function( event, ui ) {
if(ui.draggable.hasClass("template")) {
$(this).append(ui.draggable.clone())
// add item class
$(".template-slot .template").addClass("item");
// remove template class
$(".item").removeClass("ui-draggable template");
// expand to fit the slot
$(".item").addClass("expand-to-slot");
// make it draggable again
$(".item").draggable();
}
if(ui.draggable.hasClass("item")) {
$(this).append(ui.draggable);
}
}
});
The first drag and drop works okay. the problem arises on the second drag and drop. The element drags okay but when dropped it gets placed twice as far in whatever direction I drag it. So, for example, if I've dragged it 50px to the right, it drops 100px to the right. the same with up and down etc.
I suspect it's something to do with the offset being cumulative but haven't worked out why it's doing this or how to fix it.
I've created a fiddle here: https://jsfiddle.net/stefem1969/a86jmnxu/10/ to show the problem.
Hope someone can help.
Working Example: https://jsfiddle.net/Twisty/fu83zq2y/11/
JavaScript
$(function() {
function makeDrag(obj, opt) {
if (obj.hasClass("ui-draggable")) {
obj.removeClass("ui-draggable");
obj.attr("style", "");
}
if (opt === undefined) {
opt = {};
}
obj.draggable(opt);
}
makeDrag($(".template, .item"), {
helper: "clone",
});
$(".template-slot").droppable({
accept: ".template, .item",
drop: function(event, ui) {
if (ui.draggable.hasClass("template")) {
console.log("it has the template class!");
var newItem = ui.draggable.clone();
newItem.toggleClass("template item");
newItem.addClass("expand-to-slot");
newItem.appendTo($(this));
makeDrag(newItem);
}
if (ui.draggable.hasClass("item")) {
console.log("it has the item class!")
var droppableOffset = $(this).offset();
console.log("droppableOffset: ", droppableOffset);
ui.draggable.attr("style", "").appendTo($(this));
}
}
});
$(".template-store, .thagomizer").droppable({
accept: ".item",
drop: function(event, ui) {
ui.draggable.remove();
}
});
});
Part of draggable is to set a top and left when moving it around. Even if you append the item to another element, it will still have those. Clearing that can help accomplish what you're looking for.
The makeDrag() is just helpful to perform the same operations a lot.
Hope this helps.

How to get element under mouse cursor while dragging another element?

I googled and found several answers but they was all about click or mousemove events which are not suitable for my question.
Basically I allow users to drag an item from a list and drop it on a folder in another list and I want to highlight element (in the folder list) whenever an item is dragging over it. Listening to mouseenter and mouseleave events on the folder list won't work. I tried with document.elementFromPoint in the dragging event (jQuery UI's Draggable drag) but unfortunately it returns the helper element instead of the element in the folder list. I think it's correct behavior since document.elementFromPoint returns the top most element under mouse cursor. But it doesn't solve my problem :(.
$("#filelist li").draggable({
helper: "clone",
drag: function (event, ui) {
console.log(event.pageX, event.pageY);
var element = document.elementFromPoint(event.pageX, event.pageY);
// element is helper element, instead of actual element under cursor which I want.
}
});
$("#folderlist").droppable({
drop: function (event, ui) {
}
});
// These mouse events won't be triggered while dragging an item.
$("#folderlist").on({
"mouseenter": function (event) {
this.style.backgroundColor = "#1c70cf";
},
"mouseleave": function (event) {
this.style.backgroundColor = "";
}
}, "li");
Apparently, the droppable has an hover function. http://jqueryui.com/droppable/#visual-feedback
$("#folderlist").droppable({
hoverClass: "ui-state-hover",
drop: function (event, ui) {
}
});
Then add this to your css :
.ui-state-hover
{
background-color: #1c70cf;
}

When a dragged element touches other element / leave other element

I have a element (#dot) which can be dragged. The dragged element (#dot) is just allowed to be in multiple (.way)s but when (#dot) leaves this element then a function should start (for now a alert is enough). I have search on stackoverflow and on other pages but I dont find out somethings like this.
Fiddle
Here is my JS:
$(document).ready(function (){
$('#dot').draggable({
containment: "#world",
});
});
Html:
<div id="world">
<div id="dot"></div>
<div class="way">
</div>
</div>
For now an alert is enough...
My question is, how can i check if the element touches on other element?
Updated answer:
Demo: http://jsbin.com/yorohimi/4
Seems like you can use jQuery draggable and droppable for this:
JS:
$(document).ready(function () {
$('#dot').draggable();
$('.way').droppable({
accept:'#dot',
tolerance:'fit',
over:function(event,ui){
$('p').text('moved inside way');
$('#world').removeClass('green');
},
out:function(event,ui){
$('p').text('moved outside way');
$('#world').addClass('green');
}
});
});
The key is to use tolerance:fit here in droppable. Whenever #dot touches #world the color of #world is changed for visual feedback.
Following method will work only for single .way.
You can compare the position using getBoundingClientRect method and execute your code.
Fiddle: http://jsfiddle.net/9SJam/4/
JS:
$(document).ready(function () {
$('#dot').draggable({
axis: "y",
containment: "#world",
drag: function (event, ui) {
drag_handler($(ui.helper));
}
});
});
function drag_handler(elem) {
var p = elem[0].getBoundingClientRect();
var P = $('.way')[0].getBoundingClientRect();
if ((P.top > p.top) || (P.bottom < p.bottom)) {
console.log('touched');
$('#world').addClass('color');//For visual feedback
} else {
$('#world').removeClass('color'); //For visual feedback
}
}
You need to declare #world as droppable, then you can use it's over event to trigger your function, which is triggered when an accepted draggable is dragged over the droppable.
something like
$( "#world" ).droppable({
over: function() {
// Your logic
}
});

revert manual changes to 2 connected jquery ui sortable lsts

I have multiple jquery ui sortable lists that are connected and get balanced manually to N number of items whenever items are received by one list - just like in this answer: https://stackoverflow.com/a/13754827/27497
However, it appears that when you manually move items between lists (using jquery's .appendTo() or .prependTo()), these changes aren't detected by the jquery ui sortable library, and thus when you use the "cancel" command to revert the state, the manually moved items aren't placed back into their original list.
Is there a proper way to manually move an item from one list to another so that the sortable library is able to move the item back when you call $(".my-lists-selector").sortable("cancel");
Here is an example of how the items don't revert when you call .sortable("cancel") - just click the red cancel button after moving items from one list to another: http://jsfiddle.net/SUffL/3/
$(function() {
$( ".connectedSortable" ).sortable({
connectWith: ".connectedSortable",
update: function(event, ui) {
var ul1 = $("#ul1 li");
var ul2 = $("#ul2 li");
var ul3 = $("#ul3 li");
checkul1(ul1, ul2, ul3);
checkul2(ul1, ul2, ul3);
checkul3(ul1, ul2, ul3);
}
}).disableSelection();
$("#cancel-btn").click(function(){
$(".connectedSortable").sortable("cancel");
});
});
function checkul1(ul1, ul2, ul3) {
if (ul1.length > 5) {
ul1.last().prependTo(ul2.parent());
}
}
function checkul2(ul1, ul2, ul3) {
if (ul2.length > 5) {
if (ul1.length < 5) {
ul2.first().appendTo(ul1.parent());
} else {
ul2.last().prependTo(ul3.parent());
}
}
}
function checkul3(ul1, ul2, ul3) {
if (ul3.length > 5) {
ul3.first().appendTo(ul2.parent());
checkul2(ul1, ul2, ul3);
}
}
Here is a solution that stores the manually moved item along with list it started in and list it is moved to. Within the receive event handler the 2 lists are available as ui.sender and this. I created a simple balanceLists function to handle the manual move and the cancel of same
$(function () {
var listChange = {
startList: null,
item: null,
endList: null
}
$(".connectedSortable").sortable({
connectWith: ".connectedSortable",
receive: function (event, ui) {
listChange = {
startList: ui.sender,
item: ui.item,
endList: $(this)
}
balanceLists($(this), ui.sender)
}
}).disableSelection();
$("#cancel-btn").click(function () {
if (listChange.item) {
balanceLists(listChange.startList, listChange.endList)
$(".connectedSortable").sortable("cancel").sortable("refresh");
listChange.item=null;
}
});
});
function balanceLists($from, $to) {
$to.append($from.find('li').last())
}
DEMO: http://jsfiddle.net/SUffL/8/
This allows to undo one move with cancel button.

Drag the clone of dropped elements in jQuery

I have tried to drag the dropped element which is a clone of the dragged element, but when I drag the element it create a another element in the page. Here is my code..
jQuery(function() {
jQuery(".component").draggable({
// use a helper-clone that is append to 'body' so is not 'contained' by a pane
helper: function () {
return jQuery(this).clone().appendTo('body').css({'zIndex':5});
},
cursor: 'move'
});
jQuery('.ui-layout-center').droppable({
activeClass: 'ui-state-hover',
accept: '.component',
drop: function(event, ui) {
jQuery(this).append(jQuery(ui.draggable).clone().draggable());
}
});
});
Is there any missing command which makes every drag make a new clone?
You should had a class in order to indicate that element has been dropped and that you can move it but you should not clone it.
You can have a look at this fiddle : http://jsfiddle.net/scaillerie/njYqA/ .
In the handler for drop, I have just replace by this code :
if (!ui.draggable.hasClass("dropped"))
jQuery(this).append(jQuery(ui.draggable).clone().addClass("dropped").draggable());
jQuery(this).append(jQuery(ui.draggable).clone().draggable()); Did you forget .clone()

Categories