When using jQuery-UI's droppable widget, the drop function returns an "ui" object in which you can access to a "draggable" object which is the DOM element of the dragged object. But with the fullCalendar's drop function, i get the "ui" object without the "draggable" one. Here's a JSFiddle in which you can test what i'm talking about : http://jsfiddle.net/vfaethbd/
$('#calendar').fullCalendar({
header: {
left: 'title',
center: 'agendaDay,agendaWeek,month',
right: 'today prev,next'
},
droppable: true,
drop: function (date, jsEvent, ui) {
alert(JSON.stringify(ui, null, 4));
}
});
$("#droppable-area").droppable({
drop: function (event, ui) {
alert(JSON.stringify(ui, null, 4));
}
});
/* returns "draggable": {
"0": {
"jQuery111104109880250544967": 6
},
"context": {
"jQuery111104109880250544967": 6
},
"length": 1
}
*/
If you drop an event in the calendar, you won't have the draggable object, but if you drop it in the other droppable area you'll get it, since this one uses jQuery-UI.
Thanks
Implement what the external dragging example has in the drop callback:
drop: function(date) { // this function is called when something is dropped
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
// render the event on the calendar
// the last `true` argument determines if the event "sticks" (http://arshaw.com/fullcalendar/docs/event_rendering/renderEvent/)
$('#calendar').fullCalendar('renderEvent', copiedEventObject, true);
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
}
Full code example here and documentation about external events here.
Also, make sure your events and calendar are editable, for events this include:
allDay
durationEditable
startEditable
if not it may seem like your events lost the drag option
Related
During droppable out event, I need the element the mouse cursor moves to. If this element is not droppable, a default behaviour should be executed.
I tried the following:
$(dropSelector).droppable({
over: function (event, ui) {
ui.helper.css("cursor", "copy");
// Some code on drop enter here...
},
out: function (event, ui) {
// New element: mouse pointer might move to another droppable element...
// How to obtain the element where the mouse moves to?
if (/* next element is NOT droppable*/) {
ui.helper.css("cursor", "no-drop");
// Some code on drop out here...
}
},
drop: function (event, ui) {
// handle drop event
}
});
However, I could not find a way to get the element where the mouse cursor moves to during out event.. I tried event.target and event.currentTarget but they are not the elements I am looking for.
I used a different solution. Obviously the over event for the next element fires before the out event of the old element. So I check if the out target is the last element entered.
var _target = null;
$(dropSelector).droppable({
over: function (event, ui) {
_target = event.target;
ui.helper.css("cursor", "copy");
// Some code on drop enter here...
},
out: function (event, ui) {
if (_target === event.target) {
// No 'over' occurred for a new element
ui.helper.css("cursor", "no-drop");
// Some code on drop out here...
}
else {
// Some code on drop out of old element
// Perhaps some code on 'over' that has to be done after
// drop out of old element
}
},
drop: function (event, ui) {
// handle drop event
}
});
But: Can I rely on the fact that over on next element fires before out on old element?
I know I'm missing something very basic, but when using jQuery in a situation where you have stacked "droppable" DIVs on top of each other (think nested boxes), how do you allow and accept an element drop on the top most DIV and then cancel the drag/drop event so it is not also sent to the other "droppable" DIVs below?
$('#'+objectID+" .task-droppable").droppable({
accept: function(d) {
if(d.hasClass("source-task")||d.hasClass("source-sequence")){ //sequences can contain both sequences and tasks
return true;
} //end if
}, //end accept
activeClass: "isDropDest",
//hoverClass: "isDragging",
//this is used for both drag/drop and item moves
drop: function(event, ui) {
var draggableId = ui.draggable.attr("id");
var droppableId = $(this).attr("id");
//var sender_id = ui.sender.attr('id');
//var receiver_id = $(this).attr('id');
//var item_id = ui.item.attr('id');
//var above_id = ui.item.prev().attr('id');
//var below_id = ui.item.next().attr('id');
//check if this is a drag/drop or a move by looking for the object class
if(!$('#'+draggableId).hasClass('object')) {
$('#'+draggableId).css('top', '0px');
$('#'+draggableId).css('left', '0px');
createObject(draggableId, droppableId);
} else {
//handle the move - do nothing
} //end if
event.stopPropagation();
} //end drop
}); //end droppable
Sorry, not enough coffee today.
Sounds like you may need to use the greedy option
By default, when an element is dropped on nested droppables, each
droppable will receive the element. However, by setting this option to
true, any parent droppables will not receive the element.
$( ".selector" ).droppable({ greedy: true });
Working Example
I have a jquery UI drag and drop for an inventory. It works but i want it to not happen if my inventory already has 20 items in (if it's full).
I'm not that great at javascript/jquery, I can't figure out how to fix my code to do this. I want it to revert back to it's original position if the inventory is full.
Here's the function I'm using to drag/drop
function itemInSpot(drag_item,spot) {
// this is my count. i don't want it to drop an item if it's 20 or more.
var inv_count = parseInt(<? echo count($inv_item) ?>, 10);
var oldSpotItem = $(spot).find('img');
oldSpotItem.appendTo('#inventory').draggable({ revert: 'invalid' });
var item = $('<img />');
drag_item.empty().remove();
item.attr('src',drag_item.attr('src')).attr('title',drag_item.attr('title')).attr('id',drag_item.attr('id')).attr('class',drag_item.attr('class')).appendTo(spot).draggable({ revert: 'invalid' });
}
This is the code that runs the function, set on pageload:
$(document).ready(function() {
$(".weapons,.shield").draggable({ stack: "div", revert: 'invalid'});
$('#inventory').droppable();
$("#weapon_spot").droppable({ accept: '.weapons'})
$('#shield_spot').droppable({ accept: '.shield'});
$('#weapon_spot,#shield_spot,#inventory').bind('drop', function(ev,ui) { itemInSpot(ui.draggable,this); });
});
So how can I add a if inv_count > 19 then revert item back to it's original position in?
Here's a basic jsFiddle example that has six draggable/droppable items, and after the third item is dropped on the target, an alert is triggered and no other draggables are allowed in the droppable area. The elements retain thair draggable property and revert to their original position if a drop is attempted.
jQuery:
$(".ui-widget-content").draggable({
revert: "invalid"
});
$("#droppable").droppable({
drop: function(event, ui) {
$(this).addClass("ui-state-highlight").find("p").html("Dropped!");
$(ui.draggable).addClass('in');
if ($('.in').length == 3) {
$("#droppable").droppable("option", "accept", ".in");
alert('Full!');
}
}
});
I am using the UI jquery sortable plugin and have found some code that I am going to use but there is one part I don't understand. It is "onChange: "function(serialized) { widgets_positions(); }"
onChange doesn't appear in the documentation. Widgets_positions is a function that I understand about which tracks the positions of the objects being moved around. But I need to understand the 'onChange: function(serialized)' part.
$('#col').Sortable(
{
accept: 'widget',
opacity: 0.5,
helperclass: 'helper',
onChange: function(serialized) { widgets_positions(); },
handle: '.widget_title_bar'
}
);
I would imagine that is supposed to be change:
$( ".selector" ).sortable({
change: function(event, ui) { ... }
});
I have used the change event before when the order of the list is changed. ui gives you access to the dom element changed.
You could put your function call in the change event.
I've got a sortable panel (jQuery UI) on my website, but need to limit the amount of elements in each column to a maximum of 12.
I've tried a few things, but can't seem to get it to work. I need to see if 'i' is 12 or greater, and if so, don't update but I can't seem to do it!
Anyone got any advice or can push me the right way?
The jQuery is below!
function updateWidgetData(){
var items=[];
$('.column').each(function(){
var columnId=$(this).attr('id');
$('.dragbox', this).each(function(i){
var collapsed=0;
if($(this).find('.dragbox-content').css('display')=="none")
collapsed=1;
var item={
id: $(this).attr('ID'),
collapsed: collapsed,
order : i,
column: columnId
};
items.push(item);
});
});
var sortorder={ items: items };
//Pass sortorder variable to server using ajax to save state
$.post('includes/updatePanels.php', 'data='+$.toJSON(sortorder), function(response){
if(response=="success")
$("#console").html('<div class="success">Your preferences have been saved</div>').hide().fadeIn(1000);
setTimeout(function(){
$('#console').fadeOut(1000);
}, 2000);
});
}
Sortables
For connected sortables, the solution is to count the elements in each sortable when dragging starts, and disable the ones which have the maximum number of allowed elements. We need to exclude the current sortable, so we can re-order the items within and allow the current element to be dragged.
The problem here is that if we do the above on any of the sortables' events, it's already too late and disabling them won't have any effect. The solution is to do the bind the check to the mousedown event of the items themselves, which will fire before the sortable would get any control. We also need to re-enable all sortables when dragging stops.
Have a look at this example, using <ul> sortables with <li> items, the maximum number of items in each sortable is 3: http://jsfiddle.net/qqqm6/10/
$('.sort').sortable({
revert: 'invalid',
connectWith: '.sort',
stop: function(){
// Enable all sortables
$('.sort').each(function(){
$(this).sortable('enable');
});
}
});
$('.sort li').mousedown(function(){
// Check number of elements already in each sortable
$('.sort').not($(this).parent()).each(function(){
var $this = $(this);
if($this.find('li').length >= 3){
$this.sortable('disable');
} else {
$this.sortable('enable');
}
});
})
Draggables and droppables
The theory is simple, the solution is a bit tricky, there should really be a proper option in jQuery UI to cancel the operation on drop. If there is, but I missed something, please let me know.
Anyways, here's how you check for maximum count in the drop event (maximum of 4 in this example):
$('.drag').draggable({
revert: 'invalid',
stop: function(){
// Make it properly draggable again in case it was cancelled
$(this).draggable('option','revert','invalid');
}
});
$('.drop').droppable({
drop: function(event,ui){
var $this = $(this);
// Check number of elements already in
if($this.find('.drag').length >= 4){
// Cancel drag operation (make it always revert)
ui.draggable.draggable('option','revert',true);
return;
}
// Put dragged item into container
ui.draggable.appendTo($this).css({
top: '0px',
left: '0px'
});
// Do whatever you want with ui.draggable, which is a valid dropped object
}
});
See this fiddle in action: http://jsfiddle.net/qqqm6/