vkurko/calendar

Add an external event

dlpCttl opened this issue ยท 17 comments

Yo !

First big thanks for this amazing library !

I struggle to add an external event..
I used to use eventReceive with fullcalendar, how to do it with your library?

Thanks for your reply and sorry if this question has already been asked.

vkurko commented

Unfortunately external drag&drop is not supported yet. There was a discussion about this earlier.

Thank you for this very quick response.

I will see to implement it I need it..
I will come back if ever it is done!

Thank you again for the work done!

Any update on this, or is it a totally abandon idea?
In the discussion, there is a temporary solution with a workaround, but I can not make it work :/
Could we have at least a demo of that?

I wouldn't say that this feature request is very popular. Therefore, I am unlikely to do anything about this in the near future.

In the discussion, there is a temporary solution with a workaround, but I can not make it work :/

You can ask the author of the workaround in that discussion.

I was thinking of doing it myself, with very simple drag and drop functions.
When the drag happens, it will save all the necessary information that is possible to retrieve when a dropped event happens.
However, I am missing one crucial part, when the drop happens, how do I get to know where it was dropped?
I can get coordination of the mouse cursor, but I guess there is no function that would simply return the Date based on it, right?
Would you have some suggestions maybe? Or should I also try my luck in the discussion there?
This library is a very good alternative to FullCalendar, but this one feature is unfortunately missing :)

I can get coordination of the mouse cursor, but I guess there is no function that would simply return the Date based on it, right?

I think you can use dateFromPoint method.

That is exactly it, thanks :)
Here is my proof of concept.
It needs a lot of cleaning and refactoring, but it is working as a very simple drag and drop.

<main class="row">
	<div class="list">
		<div draggable="true" ondragstart="drag(event)">Task 1</div>
		<div draggable="true" ondragstart="drag(event)">Task 2</div>
		<div draggable="true" ondragstart="drag(event)">Task 3</div>
	</div>
	<div ondrop="drop(event)" ondragover="allowDrop(event)" id="ec" class="col"></div>
</main>
...
function allowDrop(ev) {
	ev.preventDefault();
}
function drag(ev) {
	const data = { title: ev.target.innerHTML, color: ev.target.style.backgroundColor };
	ev.dataTransfer.setData("text/plain", JSON.stringify(data));       //<-- store the event data
	//console.log("drag event", ev.target.innerHTML, ev);
}
function drop(ev) {
	ev.preventDefault();
			  
	const data = JSON.parse(ev.dataTransfer.getData("text/plain"));   //<-- retrieve the event data
	const x = ev.clientX;
	const y = ev.clientY;
        const position = ec.dateFromPoint(x, y);
        
        const dateStart = new Date(position.date.getTime());
	dateStart.setTime(dateStart.getTime() + dateStart.getTimezoneOffset() * 60000);     
			  
	const dateEnd = new Date(dateStart.getTime());
	dateEnd.setDate(dateEnd.getDate() + 1);			//replace with duration from event data
			  
	console.log("drop event", data, x, y, position, dateStart, dateEnd, ev);
        const newEvent = {id:data.title, title:data.title, start:dateStart, end:dateEnd, resourceIds:[position.resource?.id], color:data.color};	//fill as needed
	ec.addEvent(newEvent);
}

Edit: I guess it was too early to celebrate. When dragged into month view, it acts weird (the day number is changed and the task does not appear). Resources and timelines will also need a little bit more love.

It will need some tweaks based on the view, but I think it is good to start with.

Edit2: I am such a fool. By directly accessing the date and modifying the time to the correct timezone offset, I am also modifying the time of the date in the Month (even list) view. Easy fix by cloning it instead. I also did not notice that dateFromPoint returns resources if exists, which will work for timeline!

By directly accessing the date and modifying the time to the correct timezone offset, I am also modifying the time of the date in the Month (even list) view.

Thank you for bringing this to my attention. I think it would be correct to clone the date directly inside the library, so that the calendar cannot be broken from the outside. I will fix this in a future release.

And of course you shouldn't add the timezone offset โ€“ that will be fixed too.

If you will be digging in it, would it be possible to add an option for event, that would skip some days?
Like start from Friday to Monday, but ignore Saturday and Sunday (would be dashed over, or split into chunks the same way it goes from one day to another over midnight). I guess it is edge case, but would be interesting.
Or had an idea if color could be gradient, then it would be implemented that way.

dateFromPoint has been fixed in v3.2.2. Please check.

would it be possible to add an option for event, that would skip some days?

I think you can do this on your side by splitting the required event into 2 parts. It seems to me that this is a very specific need, but if many users ask for it, then I will consider implementing it.

Can confirm that dateFromPoint works as intended now.
How about the gradient feature in the color? That would be very fancy.

But you are right, I was thinking it would be an interesting feature, so if you had, e.g. timeline and hidden some days/hours, it would loop from the start. So you would have something like a scheduler for school/activities/etc. But the more I thought about implementation to make it universal, it made no sense. And actually end up with the same idea, splitting it by myself.

Which leads me to another question (if I should open a new issue/thread, let me know).
eventResize have endDelta.seconds argument and when resize below minimum value (30 min.), it returns where the mouse was released instead of the actual change of the block. Is it on purpose?

Events.mp4

I would expect it to return -3600 in both cases, because the task shrinks by 1 hour in both cases.
But if it is by design, I have no issue with that, since in the arguments there are old and new event timestamps, and I can calculate the difference.

And one more question, is it possible to somehow set the minimum and maximum span it can shrink or grow?
Was thinking of checking the endDelta and, if it was out of range, then changing the value in the event, but it did not work :/

Just a little sneak peek, if you are interested. No fancy CSS still, just concept.

DragAndDrop.mp4

eventResize have endDelta.seconds argument and when resize below minimum value (30 min.), it returns where the mouse was released instead of the actual change of the block. Is it on purpose?

Looks like you found another bug. Initially it worked correctly, but apparently during some changes it broke. Will be fixed in the next release. Thank you!

And one more question, is it possible to somehow set the minimum and maximum span it can shrink or grow?

Unfortunately, there is currently no suitable setting for this. There is only the option to undo resizing at the end of the action by calling the revert function, but this is not what you would like.

Just a little sneak peek, if you are interested. No fancy CSS still, just concept.

Looks great!

I was thinking of doing smth simular. But now I just added one more ressource and i load the external events into it and drag it from there. Anyway, I would still be interested if your solution works!

@vkurko Not sure if I can take the credit for the bug :D But no problem. I am glad I could help and that you are so active :)
I noticed the revert function, but I would prefer access to the event properties. So I could do something like that:
if (event.end > "20:00") event.end = "20:00"; //pseudo-code it would obviously be Date
I did not play fully with it, but would not it be possible to change it and just call redraw it or something?
Also was thinking to check and modify in the eventResizeStop, but there is not the delta information.

@CedricHH If you are asking me, then you can see the solution in the video, it works, just needs a little bit more work and making it pretty. The only issue I am facing now is that user can "overshoot" maximal value, I can call the revert function, but it just not super user-friendly :)

would not it be possible to change it and just call redraw it or something?

You can always update a specific event with updateEvent method.

Will try, thanks, I was trying to do it directly via event args. Not sure why I didnt think about it ...
Edit: Of course it works. Very simple check and correction on 3 lines of code.
Just out of curiosity, do we have some control over the visualization on the preview when resizing?