I am building custom calendar and I have the following issue: since I have to create different events on that calendar, that start and end on certain dates, and I need to resize them (left and right), I would need to know if I am starting that resize from the left side or from the right side, so I know how to set those dates.
Basically, it doesn't select the proper dates when I resize from start and when I resize from the end.
EDIT: My draggable elements also get some sort of top/left values that mess up everything, and I cannot resize it to left more than their start width (to the right side it does what it should).. It is reducing width (- 47px) instead of adding that width.
This is the code I have for resizable now:
$(".draggable").resizable({
classes: {
"ui-resizable": "highlight"
},
containment: '.calendar-row',
grid: [47, 10],
handles: 'e, w',
resize: function (event, ui) {
lastEvent = event;
},
start: function (event, ui) {
uiEvent = true;
$( event.originalEvent.target ).one('click', function(e){ e.stopImmediatePropagation(); } );
},
stop: function (event, ui) {
setTimeout(function(){
uiEvent = false;
}, 300);
$( event.originalEvent.target ).one('click', function(e){ e.stopImmediatePropagation(); } );
if(isChrome || isEdge)
{
var resizedDate = new Date($(lastEvent.toElement).attr('data-date'));
// left to right
if(ui.size.width > ui.originalSize.width)
{
console.log($(lastEvent.toElement).attr('id'));
console.log($(lastEvent.toElement).attr('data-date'));
}
else{
var elemFromPoint = document.elementFromPoint(lastEvent.pageX, lastEvent.pageY).previousElementSibling;
console.log($(elemFromPoint).attr('id'));
console.log($(elemFromPoint).attr('data-date'));
}
}
if(isFirefox)
{
var resizedDate = new Date($(lastEvent.target).attr('data-date'));
$(lastEvent.target).hide();
// left to right
if(ui.size.width > ui.originalSize.width)
{
var elemFromPoint = document.elementFromPoint(lastEvent.pageX, lastEvent.pageY);
console.log($(elemFromPoint).attr('id'));
console.log($(elemFromPoint).attr('data-date'));
}
else{
var elemFromPoint = document.elementFromPoint(lastEvent.pageX, lastEvent.pageY).previousElementSibling;
console.log($(elemFromPoint).attr('id'));
console.log($(elemFromPoint).attr('data-date'));
}
$(lastEvent.target).show();
}
}
});
Related
I have some draggable <div> on my website.
I want to disable the drag option above a certain point on my page.
When I even just try to monitor the drag event and alert something I don't succeed.
This how I made it draggable (Divs with "screen" class):
//Resizable + Draggable
let resizeOpts = {
handles: "all" ,autoHide:true
};
$('.screen')
.draggable()
.resizable(resizeOpts);
$('.screen')
.resizable({
start: function(e, ui) {
alert('resizing started');
},
resize: function(e, ui) {
},
stop: function(e, ui) {
alert('resizing stopped');
}
});
console.log(arrScreens);
}
This when I try to monitor drag event:
var elements = document.getElementsByClassName("screen");
for (var i = 0; i < 30; i++) {
elements[i].addEventListener('dragstart', function() {
alert("You dragged the element");
}, false);
}
** Also if I tried addeventlistener on body tag I didn't success to monitor this event. On other events, it worked.
https://jsfiddle.net/ianderso222/y9ynouxs/36/
I hope this makes sense, If I need to elaborate I will do so.
Right now the code is working pretty well, doing everything I need it to except this one issue. I just need to alert the order that the squares have been dropped in, after all 4 have been placed.
So, if square4 is placed in the large container, that would show up first in the alert. If square2 is in the last, smallest box it would be last in the list, and so on.
I would use sortable but I am afraid it would not work with the current setup. The resizing to different sized containers would not work, or at least I was not able to get it to work. If there is a way to keep the current structure of resizing to fill container and sliding into place I would say do that, but from everything I have seen I feel I would have to essentially start from scratch.
Here is the JavaScript, pardon the messy code:
$('.holderList li').droppable({
drop: function(event, ui) {
var droppable = $(this);
var draggable = ui.draggable;
console.log(draggable.attr('id') + ' is ' + droppable.attr('id'));
var $this = $(this);
ui.draggable.position({
my: "center",
at: "center",
of: $this,
using: function(pos) {
$(this).animate(pos, 200, "linear");
}
});
ui.draggable.addClass('dropped');
ui.draggable.data('droppedin', $(this));
$(this).droppable('disable');
setTimeout(function() {
var dragID = ui.draggable;
if (!$(".ui-droppable").not(".ui-droppable-disabled").length) {
alert(draggable.attr('id'));
}
}, 400);
},
});
$(".square").draggable({
stack: ".square",
revert: function(event, ui) {
//overwrite original position
$(this).data("ui-draggable").originalPosition = {
width: 50,
height: 50
}
//return boolean
return !event;
},
drag: function(event, ui) {
var draggable = $(this).data("ui-draggable");
$.each(draggable.snapElements, function(index, element) {
ui = $.extend({}, ui, {
snapElement: $(element.item),
snapping: element.snapping
});
if (element.snapping) {
if (!element.snappingKnown) {
element.snappingKnown = true;
draggable._trigger("snapped", event, ui);
}
} else if (element.snappingKnown) {
element.snappingKnown = false;
draggable._trigger("snapped", event, ui);
}
});
if ($(this).data('droppedin')) {
$(this).data('droppedin').droppable('enable');
$(this).data('droppedin', null)
$(this).removeClass('dropped')
}
},
snap: ".holder",
snapMode: "inner",
snapTolerance: 8,
snapped: function(event, ui) {
var squareWidth = ui.snapElement.width();
var squareHeight = ui.snapElement.height();
ui.helper.css({
width: squareWidth,
height: squareHeight
});
}
});
Take a look at my solution:
Demo
First it assigns a data-current attribute to the droppable holder on every drop and sets it to the id of the draggable.
Then it itterates trough all the .holder elements and prints their data-current
Simple but works.
// On single drop
drop: function(event,ui){
...
droppable.attr('data-current', draggable.attr('id') );
}
//On all dropped
$('.holder').each(function(el){
console.log($(this).attr('data-current'));
});
I am tring to make a movable sharebox, and i want to memorize the position in wich the user locates the sharebox with localstorage or cookie. But my problem is that after the first drag you cannot drag the box again. And also i cannot use the ui.position().left command. It wont return anything.
html code:
<div id="draggable" class="ui-widget-content">Drag me around</div>
script
function local_storage()
{
var test = 'test';
try
{
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
}
catch(e)
{
return false;
}
}
$( "#draggable" ).draggable({
stop: function(event, ui) {
if (local_storage() === true)
{
var Stoppos = $(this).position();
localStorage.setItem('left', Stoppos.left);
localStorage.setItem('top', Stoppos.top);
//localStorage.setItem('left', ui.position().left);
//localStorage.setItem('top', ui.position().top);
setCookie('sharebox','',-1);
}
else
{
//setCookie('sharebox', top, ui.position().top);
//setCookie('sharebox', left, ui.position().left);
setCookie('sharebox', top, Stoppos.top);
setCookie('sharebox', left, Stoppos.left);
}
}
});
I made a jsfiddle for example:
http://jsfiddle.net/maguse/4x8jeo0x/
Can anyone tell me why it stops and how to make it work?
Thank you
You can either ship your own funcion to set cookies or use jQuery cookie plugin.
Instead of saving multiple items, you can directly save the entire position object and retrieve it as shown below:
var lastPosition = JSON.parse(localStorage.getItem("lastPosition")) || JSON.parse($.cookie("lastPosition"))
if (lastPosition) {
$("#draggable").css({
"position": "absolute",
"top": lastPosition.top,
"left": lastPosition.left
});
}
$("#draggable").draggable({
stop: function (event, ui) {
if (typeof localStorage)
localStorage.setItem('lastPosition', JSON.stringify($(this).position()));
else
$.cookie('lastPosition', JSON.stringify($(this).position()));
}
});
Updated fiddle
I'm trying to implement something very close to what the 'Sortable Widget' would do, though I can't use it because of other things that doesn't work with the premade widget.
So I'm trying to recreate it's functionality with draggable and droppable elements:
$(".Element").draggable({
helper: 'original',
drag: function(event, ui) {
ElementWidth = $(this).outerWidth(true);
if($(this).prev().length){
LeftElementWidth = $(this).prev().outerWidth(true);
LeftElementLeftOffset = $(this).prev().offset().left;
if(parseFloat(ui.offset.left+(ElementWidth/2)) < parseFloat(LeftElementLeftOffset+(LeftElementWidth/2))){
$(this).prev().before($(this));
}
}
if($(this).next().length){
RightElementWidth = $(this).next().outerWidth(true);
RightElementLeftOffset = $(this).next().offset().left;
if(parseFloat(ui.offset.left+(ElementWidth/2)) > parseFloat(RightElementLeftOffset+(RightElementWidth/2))){
$(this).next().after($(this));
}
}
}
});
$("#Container").droppable({ accept: '.Element' });
It works fine, except for that the draggable-helper doesn't stay underneath the mouse-cursor when I move it's element to the next position.
Check out this fiddle:
http://jsfiddle.net/5qFhg/15/
You'll see what happens when you try to sort the green boxes. How can I keep the helper in position?
http://jsfiddle.net/margaret_/XM6f8/1/
Is this what you are looking for? Are you okay with using knockout? I can't add comments 'cause I don't have 50 reputation.
<input data-bind="value: name, visibleAndSelect: $data === viewModel.selectedTask(), event: { blur: function() { viewModel.selectTask(''); } }" />
Use parent and previous location to mimic the function.
ko.bindingHandlers.sortableList = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
$(element).data("sortList", valueAccessor()); //attach meta-data
$(element).sortable({
start: function(event, ui) {
//track the original position of the element
var parent = ui.item.parent();
var prev = ui.item.prev();
//create a function to move it back (if it has a prev sibling, insert after it, otherwise put it at the beginning)
ui.item.moveItemBack = prev.length ? function() { ui.item.insertAfter(prev); } : function() { parent.prepend(ui.item); };
},
update: function(event, ui) {
var item = ui.item.data("sortItem");
if (item) {
//identify parents
var originalParent = ui.item.data("parentList");
var newParent = ui.item.parent().data("sortList");
//figure out its new position
var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
if (position >= 0) {
//move the element back to its original position and let KO handle adding it to the new parent
if (originalParent !== newParent) {
ui.item.moveItemBack();
}
//place item in the proper position
newParent.remove(item);
newParent.splice(position, 0, item);
}
}
},
connectWith: '.container'
});
}
Do you want the divs to appear side by side?
I have two jquery.ui draggables. I am constraining their movement to the y-axis. If one is dragged to a certain y-position, I want the other to automatically move to the same y-position and vice versa. Has anyone ever linked two of these together before?
Updated: Script and demo updated so it is no longer restricted to the y-axis while dragging.
This script looks for the class "group" followed by a number to drag/drop these combined objects. I posted a demo here.
HTML
<div class="demo">
<div id="draggable">
<p>Drag from here</p>
<div class="dragme group1"><img src="image1.jpg"><br>Group 1</div>
<div class="dragme group1"><img src="image2.jpg"><br>Group 1</div>
<div class="dragme group2"><img src="image3.jpg"><br>Group 2</div>
<div class="dragme group2"><img src="image4.jpg"><br>Group 2</div>
</div>
<div id="droppable">
<p>Drop here</p>
</div>
</div>
Script
$(document).ready(function() {
// function to get matching groups (change '.group' and /group.../ inside the match to whatever class you want to use
var getAll = function(t) {
return $('.group' + t.helper.attr('class').match(/group([0-9]+)/)[1]).not(t);
};
// add drag functionality
$(".dragme").draggable({
revert: true,
revertDuration: 10,
// grouped items animate separately, so leave this number low
containment: '.demo',
stop: function(e, ui) {
getAll(ui).css({
'top': ui.helper.css('top'),
'left': 0
});
},
drag: function(e, ui) {
getAll(ui).css({
'top': ui.helper.css('top'),
'left': ui.helper.css('left')
});
}
});
$("#droppable").droppable({
drop: function(e, ui) {
ui.draggable.appendTo($(this));
getAll(ui).appendTo($(this));
}
});
});
I haven't done this before, but I suggest using the drag event to adjust the position of the respective other element:
$('.selector').draggable({
...,
drag: function(event, ui) {
},
...
});
The ui object will contain information (in the property ui.offset) you can use to manually reposition the other element.
https://forum.jquery.com/topic/dragging-a-group-of-items-alsodrag-like-alsoresize
I found an extension for UI draggable(). It works in the same way as 'alsoResize' for UI resizable(), i.e.
$('.selector').draggable({ alsoDrag: '.selected' });
Add the plugin code after main jquery-ui library.
$.ui.plugin.add( 'draggable', 'alsoDrag', {
start: function() {
var that = $(this).data("ui-draggable"),
o = that.options,
_store = function (exp) {
$(exp).each(function() {
var el = $(this);
el.data("ui-draggable-alsoDrag", {
top: parseInt(el.css("top"), 10),
left: parseInt(el.css("left"), 10)
});
});
};
if (typeof(o.alsoDrag) === "object" && !o.alsoDrag.parentNode) {
if (o.alsoDrag.length) { o.alsoDrag = o.alsoDrag[0]; _store(o.alsoDrag); }
else { $.each(o.alsoDrag, function (exp) { _store(exp); }); }
}else{
_store(o.alsoDrag);
}
},
drag: function () {
var that = $(this).data("ui-draggable"),
o = that.options,
os = that.originalSize,
op = that.originalPosition,
delta = {
top: (that.position.top - op.top) || 0,
left: (that.position.left - op.left) || 0
},
_alsoDrag = function (exp, c) {
$(exp).each(function() {
var el = $(this), start = $(this).data("ui-draggable-alsoDrag"), style = {},
css = ["top", "left"];
$.each(css, function (i, prop) {
var sum = (start[prop]||0) + (delta[prop]||0);
style[prop] = sum || null;
});
el.css(style);
});
};
if (typeof(o.alsoDrag) === "object" && !o.alsoDrag.nodeType) {
$.each(o.alsoDrag, function (exp, c) { _alsoDrag(exp, c); });
}else{
_alsoDrag(o.alsoDrag);
}
},
stop: function() {
$(this).removeData("draggable-alsoDrag");
}
});
You would have to explicitly set the Y-Axis of both the elements.
For this either in the event handler functions of both the elements you will have to set Y-Axis or bind both the elements with same function.
Happy coding.
Here is a simplified version of the code mentioned in the marked answer(for dummies like me):
In HTML
<div id="div1" class="group">...</div>
<div id="div2"class="group">...</div>
In Script tag
$(document).ready(function(){
//to get the group
var getGroup = function() {
return $(".group");
}; // add drag functionality
$(".group").draggable({
revertDuration: 10,
// grouped items animate separately, so leave this number low
containment: "window",
scroll: false,
stop: function(e, ui) {
getGroup(ui).css({
'top': ui.helper.css('top'),
});
},
drag: function(e, ui) {
getGroup(ui).css({
'top': ui.helper.css('top'),
'left': ui.helper.css('left')
});
}
});
});