drag fancytree node to an external droppable - javascript

I have a fancytree populated with some json. I also have a droppable div. I want to be able to drag nodes within the tree (ie to move stuff about within the contained hierarchy) and I want to be able to drag stuff from the tree into my external droppable div.
How can I do this?
Here's what I have:
My html:
<div id="tree"></div>
<div id="droppable">
stuff
</div>
dnd initialisation options:
{
autoExpandMS: 400,
focusOnClick: true,
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
preventRecursiveMoves: true, // Prevent dropping nodes on own descendants
dragStart: function(node, data) {return true;},
dragEnter: function(node, data) {return true;},
dragDrop: function(node, data) {data.otherNode.moveTo(node, data.hitMode);},
draggable: {
containment: 'document',
scroll : false,
scrollSpeed: 7,
scrollSensitivity: 10,
}
},
droppable initialisation
$('#droppable').droppable({
onDrop : function(e,source){
alert('dropped: '+source.textContent);
window.dropped = source;
window.event = e;
},
});
Extensions:
I'm making use of ["dnd","edit","contextMenu"] extensions. I'm mentioning this in case there is some conflict I am not aware of... I did however disable the edit and contextMenu to no avail.
Behavior:
The contextMenu and edit extensions work fine.
I can drag and drop items within the tree to reorder nodes.
I cannot drag stuff out of the tree
with scroll: true the tree just gets some scrollbars that scroll to infinity as I drag over the edge
with scroll: false the tree scrollbars behave the same but no actual scrolling occurs
containment seems to have no effect
Included resources:
jquery.js jquery-ui-1.11.0.js
jquery.fancytree-all.css
jquery.contextMenu.css
jquery.contextMenu-1.6.5.js
jquery.fancytree.contextMenu.js
fancytree.min.css

To prevent scrolling inside the tree container:
$("#tree").fancytree({
...
dnd: {
...
draggable: {
scroll: false
},
and custom CSS
ul.fancytree-container {
position: inherit;
}
To make containment work:
$("#tree").fancytree({
dnd: {
...
draggable: {
revert: "invalid"
scroll: false,
appendTo: "body", // Helper parent (defaults to tree.$container)
helper: function(event) {
var $helper,
sourceNode = $.ui.fancytree.getNode(event.target),
$nodeTag = $(sourceNode.span);
$helper = $("<div class='fancytree-drag-helper'><span class='fancytree-drag-helper-img' /></div>")
.append($nodeTag.find("span.fancytree-title").clone());
// Attach node reference to helper object
$helper.data("ftSourceNode", sourceNode);
// we return an unconnected element, so `draggable` will add this
// to the parent specified as `appendTo` option
return $helper;
},
},
}
[...]
});

There is an example that can be found under the tests directory of the fancytree source that does the exact same thing. Take a look at it here: http://wwwendt.de/tech/fancytree/test/test-ext-dnd.html
Hope this helps.

I have faced the same issue with dragging elements out of the tree and ended up with some quick css hack for fancytree-container element:
ul.fancytree-container {
overflow: visible;
}

The problem is that FancyTree uses its own draggable helper which is attached to the tree element. See _onDragEvent in jquery.fancytree.dnd.js (line 389).
I got round this by hacking the code to append the helper to the body i.e.
$("body").append($helper);
...instead of...
$("ul.fancytree-container", node.tree.$div).append($helper);

Related

jQuery draggable with position conditionals

Trying to figure out how to be able to drag the red square ONLY AFTER the blue square has been dragged to the other end of its parent.
Also wondering if it is possible (in a separate scenario) to have the red square mirror the blue square when the blue square is dragged.
https://jsfiddle.net/t167y2ga/14/
$(function() {
$("#draggable_left").draggable({
containment: "parent",
});
});
$(function() {
$("#draggable_right").draggable({
containment: "parent",
});
});
You can use stop event:
stop:function(ev,ui){
if(ui.position.left === 150) {
$("#draggable_right").draggable({
containment: "parent",
});
}
Something like this will do the first part:
Fiddle
To achieve your first goal
be able to drag the red square ONLY AFTER the blue square has been
dragged to the other end of its parent
You just need to apply the draggable to the html element after the stop event is fired from the first draggable element. Sample code is:
$(function() {
$("#draggable_left").draggable({
containment: "parent",
stop: function(e, ui) {
$("#draggable_right").draggable({
containment: "parent",
});
},
});
});
See the JSFiddle working example here
EDIT: In case you want to disable the draggable when blue element is not in the right side, see this other JSFiddle

z-index stacking issue on draggable element (jQuery UI)

I'm having an issue in a jQuery UI app I'm writing (a klondike solitaire game) that happens when I'm attempting to drag a part of a flipped over stack from one stack to another. You can see this illustrated in the screenshot below:
The app in its entirety can be found in this Fiddle: http://jsfiddle.net/damo_s/hy2dvL1u/
I have an idea of what's going wrong but not sure how to engineer it to work as expected.
I initially tried to fix it by adding a class to the hovered over droppable but this only works to the extent that I have to have the draggable at least 50% over the droppable (because I'm using intersect mode on the tolerance option) before the draggable comes to the front. The relevant code:
$('.drop-area').droppable({
over: function (event, ui) {
$(this).closest('.main-stack').addClass('droppable-above');
},
out: function (event, ui) {
$('.main-stack').removeClass('droppable-above');
},
drop: function (event, ui) {
$('.main-stack').removeClass('droppable-above');
...
My guess of what's going on is that the stacks with class .main-stack are absolutely positioned layers with their own z-index values (though not explicitly set in my css) and thus the z-index of the draggable has no bearing on whether it will be above or below a particular .main-stack
Any further clarification on what's going on and what can be done to fix it would be much appreciated.
A solution came to me shortly after I posted the question.
I added this to the start: method of the draggable initialization:
if ($(this).closest('.main-stack').length) {
$(this).closest('.main-stack').addClass('dragging-card');
$(this).closest('.main-stack').siblings().removeClass('dragging-card');
}
So my code became:
$('.card').draggable({
start: function (event, ui) {
positionTop = $(this).css('top');
// On drag start check each stack for an empty stack
$('.main-stack').each(function () {
if (!$(this).find('.card').length) {
$(this).droppable('option', 'disabled', false);
return false;
}
});
// If dragging from a main stack
if ($(this).closest('.main-stack').length) {
// Set the class of the draggable's containing stack
$(this).closest('.main-stack').addClass('dragging-card');
$(this).closest('.main-stack').siblings().removeClass('dragging-card');
}
},
And my CSS changed to:
.under-card {
z-index: 1000!important;
}
.ui-front, .top-card {
z-index: 1001!important;
}
.dragging-card {
z-index: 1002!important;
}
.ui-draggable-dragging {
z-index: 1003!important;
}

jQuery draggable bug (element not in line with cursor)

EDIT: JSFIDDLE: http://jsfiddle.net/h9yzsqfr/
--
Code:
elem.editor.find("div.ui-widget").draggable(
{
handle:"div.content",
containment:elem.editor,
snap:"*",
start: function(e,ui)
{
$(ui.helper).addClass("dragging");
},
drag: function(e,ui)
{
checkTop(ui);
if($(ui.helper).parents("div.lo-content").length > 0)
{
$(ui.helper).appendTo(elem.editor);
ui.position = { 'top': e.pageY, 'left': e.pageX };
}
},
stop: function(e,ui)
{
oldWidget.saveState($(ui.helper),1);
setTimeout(function() {
$(ui.helper).removeClass("dragging");
}, 300);
}
});
I have some draggable objects within a container defined by elem.editor; however I have some other draggable objects inside div.lo-content which is also inside elem.editor.
Whenever an object inside div.lo-content is dragged, it should reattach to the elem.editor container which is working fine; however as demonstrated in the following GIF (below), it is not setting the position of the draggable object to where the mouse cursor is.
What is a workaround for this problem?
The problem is your width: 100% and the containment option. As soon as its appended to body it stays 100%, but of the body, then it gets smaller but the containment has already been calculated.
One way to solve it is to reset containment. There are probably different ways to do it, one way could be like this:
start: function (e, ui) {
if ($(this).parents(".inner").length > 0) {
$(ui.helper).addClass("dragging");
ui.helper.css({
'width': '100px',
'left': '0px',
'top': '0px'
});
ui.helper.data()['ui-draggable'].containment = [0,0,$('body').width(), $('body').height()]
ui.helper.appendTo("body");
}
},
http://jsfiddle.net/puurqx8r/6/
connectToSortable 
It's a  Selector that Allows the draggable to be dropped onto the specified sortables. If this option is used, a draggable can be dropped onto a sortable list and then becomes part of it. Note: The helper option must be set to "clone" in order to work flawlessly. Requires the jQuery UI Sortable plugin to be included.
Code examples:
Initialize the draggable with the connectToSortableoption specified:
$( ".selector" ).draggable({
connectToSortable: "#my-sortable"
cursorAt:{top: 5, left: t}
});
Use cursorAt: top:, left: and appendTo: 'body'
See my answer with example here.
jQuery draggable shows helper in wrong place after page scrolled
I had the same problem. This is caused by the use of margins to center elements. Try using position absolute!
I removed position:absolute on dragable object

Jquery Draggable - How do I make a dragged element snap in pixel increments

For my application, after an element is dragged and snapped to the droppable zone I need to continue to allows for that dragged item to be moved vertically only. I have already gone ahead and done this, but I also need for that item to only be dragged and snapped to pixel increments. How can this be done?
For example, I have a timeline and I need the elements to snap to 15 minute increments. I need to know if this is possible with the draggable function or do I need to come up with some slider hybrid? I'd rather not use some hybrid approach if possible.
Code Snippet:
$(".activity_link").draggable({
"snap": ".trek_slider",
"snapMode": "inner",
// "snapTolerance" : 30,
"revert": function (event, ui) {
// on older version of jQuery use "draggable"
// $(this).data("draggable")
// on 2.x versions of jQuery use "ui-draggable"
// $(this).data("ui-draggable")
$(this).data("uiDraggable").originalPosition = {
top: 0,
left: 0
};
$(this).draggable("option", "axis", false);
// return boolean
return !event;
// that evaluate like this:
// return event !== false ? false : true;
}
});
$(".trek_slider").droppable({
"tolerance": "touch",
"over": function (event,
ui) {
var left_position = parseInt($(ui.draggable).css("left"));
$(ui.draggable).find(".activity_caret").show();
$(ui.draggable).draggable("option", "axis", "y");
}
});
Try this
$( ".your_div" ).draggable({ grid: [ 1,1 ] });
In above example it will be draggedx by only one pixel in each direction
Please Note: Do not forget to add your other options.

Allow the draggable content exceed but not within the parent boundary in Jquery?

I am using Jquery ui and it provide a function for me to make draggable content. It has an option 'containment' that force the draggable item move within the box.
However, for my case, the content (image) must exceed the screen , how can I force it not to drag inside the screen?
Thanks
$("#popup").draggable({
addClasses:true,
scrollSpeed: "200",
containment: "parent",
//appendTo: "body",
helper: function(){
// Create an invisible div as the helper. It will move and
// follow the cursor as usual.
return $('<div></div>').css('opacity',0);
},
drag: function(event, ui){
// During dragging, animate the original object to
// follow the invisible helper with custom easing.
var p = ui.helper.position();
$(this).stop().animate({
top: p.top,
left: p.left
},1000,'easeOutCirc');
}
});

Categories