Trigger Javascript event on different target - javascript

I have a element which adds a child to itself when a mousedown or touchstart event occurs. This child is resizable (jQuery ui widget). I use http://touchpunch.furf.com/ wich enables jquery-ui widgets for touch devices.
I want to resize the child when it gets created without lifting the mouse/touch and clicking again. It works for mouse devices but i fail to trigger it when using a touch device.
Check the snippet (works for mouse, fails with touch).
Mousedown on blue element (red element is created)
Keep mouse down and drag to the right (red element gets resized)
I fail making it work for a touch device.
I create the element on touchstart, but i am not able to resize it whithout lifting my finger.
I basically want to achieve the same with touch as with the mouse. Problem is I don't know how the event must look like which I have to trigger on the resize-handle.
I check if it is a touch event and try to change the event.target but this does not work.
if (event.type === "touchstart") {
console.log("here i am stuck")
event.target = handler[0];
item.trigger(event);
}
$(function(){
$(document).on("mousedown touchstart", ".resizeCreator", function(event){
if ($(this).find("div").length){
return;
}
//Add resizable div
$(this).append("<div>resize me</div>");
$(this).find("div").resizable({handles: "e"});
simulateHandleEvent($(this).find("div"), event)
});
$(document).on("click", "button", function(){
$(".resizeCreator").find("div").remove();
});
})
var simulateHandleEvent = function(item, event){
var handler = item.find(".ui-resizable-e").first();
if (event.type === "touchstart") {
console.log("here i am stuck")
event.target = handler[0];
item.trigger(event);
}else{
handler.trigger("mouseover");
handler.trigger({
type: "mousedown",
which: 1,
pageX: handler.offset().left,
pageY: handler.offset().top
});
}
}
.resizeCreator{
width:200px;
height:200px;
padding:5px;
border:1xp solid black;
background-color:blue;
}
.resizeCreator div{
background-color:red;
display:inline-block;
padding:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>
<div class="resizeCreator">
</div>
<button>reset</button>

Related

How to manually trigger the mouseleave event on a mobile device

I want to change a link color to orange on hover.
On a mobile device, when the user touches the link, it becomes orange and will remain orange until the user clicks away. So I want to manually trigger the mouseout event so that the link looses it's hover effect after 1 seconds.
This is what I have tried but the link remains orange after 1 second:
$(window).on('load', function() {
$('a').on('click', function() {
// on a mobile device, I want the hover effect to end after 1 seconds
window.setTimeout(function() {
$('a').trigger('mouseout');
}, 1000);
});
});
a {
font-size: 2rem;
}
a:hover {
color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a href='#'>Test</a>
</div>
Note: this is a simplified example, in my code I am not using a timer instead I want to trigger the mouseout event on ajaxcomplete
$(document).on('ajaxComplete', function () {
$('a').trigger('mouseout');
});
The problem is trying to force a mouseout event doesn't seem to work on a touch device.
The series of events that is fired on a touch device starts with a touchstart event - see e.g. MDN
If the browser fires both touch and mouse events because of a single user input, the browser must fire a touchstart before any mouse events.
This snippet remembers that the user has started a touch event and instead of acting on mouse events it sets a class which changes the text color. The same is done on mouse events, which are only acted on when the user is not appearing to be using a touch device on this element.
While it would seem logical to look subsequently for the touchend event on the element, it seems that if the user does a long touch on it, given it is an anchor element, the touchend event is not fired on the element when they remove their finger/pointing device. It is however still fired on the window and so we catch that event and remove the hover class.
let usingTouch = false;
const a = document.querySelector('a');
a.addEventListener('touchstart', function() {
usingTouch = true;
a.classList.add('hover');
});
window.addEventListener('touchend', function() {
usingTouch = true;
setTimeout(function() {
a.classList.remove('hover');
}, 1000);
});
a.addEventListener('mouseover', function() {
if (!usingTouch) a.classList.add('hover');
});
a.addEventListener('mouseout', function() {
if (!usingTouch) a.classList.remove('hover');
});
a {
font-size: 2rem;
}
.hover {
color: orange;
}
<div>
<a href='#'>Test</a>
</div>
a {
font-size: 2rem;
}
a:hover {
color: myanimation 1s 1;
-webkit-animation:myanimation 1s 1;
}
#keyframes myanimation
{
0% {color:orange;}
100% {color:orange;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a href='#'>Test</a>
</div>
This is solvable via a CSS animation, see the snippet above.

Event handler for canvas mouse enters while being clicked

I would like to know how to implement a JQuery event listener for an HTML 5 canvas element where a mouse cursor enters the canvas while being clicked.
Keep a flag when mousedown and mouseup, then check this when user hover on the canvas.
var mouseDown = false;
$(document).mousedown(function() {
mouseDown = true;
});
$(document).mouseup(function() {
mouseDown = false;
});
var canvasHover = false;
$('canvas').on('mouseenter', function() {
$('span').html(mouseDown ? 'true' : 'false');
});
canvas {
background:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas width="300" height="300"></canvas>
<hr />
mouse is down: <span></span>
You can bind mousedown\mouseup events to documentand mouseenter event on canvas.
I'd suggest to use capturing phase instead (which jQuery doesn't support) to avoid any propagation event stopped in some way.
See an example:
document.addEventListener('mousedown', function(e) {
$(this).data('mouseHold', e.which);
}, true);
document.addEventListener('mouseup', function(e) {
$(this).data('mouseHold', false);
}, true);
$('canvas').on('mouseenter', function() {
if ($(document).data('mouseHold')) {
console.log('holding mouse button ' + $(document).data('mouseHold'));
}
});
canvas {
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas></canvas>

How can I make a nested element not draggable in a draggable container?

I'm using HTML5 drag and drop on a parent container, but I want to disable the drag effect on some of its children, specifically an input so that users can select/edit input content easily.
Example:
https://jsfiddle.net/Luzub54b/
<div class="parent" draggable="true">
<input class="child" type="text" value="22.99"/>
</div>
Safari seems to do this for inputs by default so try it on Chrome or Firefox.
I was looking for something similar and found a possible solution using the mousedown and mouseup events. It's not the most elegant solution but it's the only one that worked consistently for me on both chrome and firefox.
I added some javascript to your fiddle:
Fiddle
;
(function($) {
// DOM Ready
$(function() {
$('input').on('mousedown', function(e) {
e.stopPropagation();
$('div.parent').attr('draggable', false);
});
$(window).on('mouseup', function(e) {
$('div.parent').attr('draggable', true);
});
/**
* Added the dragstart event handler cause
* firefox wouldn't show the effects otherwise
**/
$('div.parent').on({
'dragstart': function(e) {
e.stopPropagation();
var dt = e.originalEvent.dataTransfer;
if (dt) {
dt.effectAllowed = 'move';
dt.setData('text/html', '');
}
}
});
});
}(jQuery));

Get notified about dragged images within a contenteditable div

I have a div which has contenteditable="true" and which contains some html. This html may include images.
Since contenteditable="true" the user can move images by dragging them to a new position. But I need my code to be notified each time a image is moved, in a way where I get both the image element which is being moved, and the target node where the image is dropped. How do I do that?
My current solution adds a Drop listener to my div element which is contenteditable, and then I do get a drop event each time the user moves an image, but I can't get the dom node with the image which the user moved.
Also: Dragging an image, seems to copy the DOM node, instead of moving it. Is this true? (Tested in firefox).
I would suggest a following pure JavaScript solution
HTML:
<div id="space" contenteditable="true">
Hello <img width="300" class="contentImg" src='http://www.independent.co.uk/incoming/article9859555.ece/alternates/w620/Dr-Talyor.jpg'/> dude!
</div>
CSS:
#space {
width: 500px;
height: 500px;
background-color: #000000;
color: #ffffff;
}
JavaScript:
var draggedImg;
document.addEventListener("dragstart", function( event ) {
// IE uses srcElement, others use target
var targ = event.target ? event.target : event.srcElement;
if (targ.className == 'contentImg'){
draggedImg = event.target;
}
}, false);
document.addEventListener("dragend", function( event ) {
if(draggedImg){
alert("It's moved!");
console.log('Here is data', draggedImg);
draggedImg = null;
}
}, false);
You'll find an image node in draggedImg variable.
Please review a working example here: http://jsfiddle.net/o09hLtch/2/
jQueryUI features draggable and droppable interactions. Draggable has drag event, which gives you the dragged element and droppable has drop event, which gives you the dropped element as well as where it was dropped.
Quick example: clickety
$('#content .dr').draggable(
{
addClasses: false,
drag: function(event, ui)
{
$('#notify').text('Bird (#' + $(this).attr('id') + ') being dragged: ' + JSON.stringify(ui));
},
stop: function(event, ui)
{
$('#notify').text('');
}
});
I think You looking for this,
$(function () {
$(".image").draggable({helper: 'original'});
$(".container").droppable({
drop: function (event, ui) {
$(this).append(ui.draggable.css({position: 'static'}));
alert('dropped!');
}
});
});
For JSFiddle Demo Let's see
Good Luck ['}

HTML5 drag and drop events - dragLeave fires before drop

In drag and drop the dragLeave event sometimes fires before the drop event.
This is causing problems because the target is getting the listeners in dragEnter with dragLeave and drop removing the listeners. If dragLeave fires before drop, then there is no listener for the drop.
I think the reason has something to do with another contra-intuitive: the dragEnter sometimes fires multiple times for the same target, even with propagation off. With multiple dragEnters, one would spawn a drop while the others would spawn a dragLeave. If this is the case, perhaps I could associate the dragLeave with the dragEnter - but I see no means of that coordination.
function dragEnter( e ) {
e.stopPropatation();
// is multiple fires of dragEnter for same cell
if( curCell == this ) return;
curCell = this;
curCell.addEventListener( 'drop', drop, true );
curCell.addEventListener( 'dragover', dragOver, true );
curCell.addEventListener( 'dragleave', dragLeave, true );
...
}
function dragLeave( e ) {
e.stopPropagation();
curCell.removeEventListener( 'drop', drop, true );
curCell.removeEventListener( 'dragover', dragOver, true );
curCell.removeEventListener( 'dragleave', dragLeave, true );
}
function drop( e ) {
// do the actual work
dragLeave( e );
}
Here's a list of calls:
begin drag dragstart
drag enter: this=e9 - e.target=IMG
drag enter: this=e9 - e.target=TD
drag enter: this=e8 - e.target=TD
drag enter: this=e8 - adding listeners
drag enter: this=e8 - e.target=IMG
drag leave: this=e8
clearing listeners: this=e8
If the "clearing listeners" were not performed, the next step would have been:
drop: this=e8
try this
<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">
#div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Drag it</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="drag1" src="img_logo.gif" draggable="true" ondragstart="drag(event)" width="336" height="69">
</body>
</html>
There's rarely a reason to manage your event listeners in this way.
If you bind to drop, dragover, dragleave at the same time as you bind to dragenter do you still see the problem?
The HTML dnd api is a little bit weird when you first look at it. Depending on what you are trying to do something simple like
onDragOver=function(e) { e.stopPropagation() }
onDrop=function(e) { /* handle drop */ }
may be all the listeners you need.

Categories