I am looking for a way to allow a user to cancel a mouse drag operation by pressing the ESC key.
Can this be done using Javascript?
Thank you
Update
When the mouse is dragging a div element over a droppable area, pressing the ESC key should drag the element to an area that is not droppable. Once the element is dragged to a non-droppable area, I invoke a "mouseup" event on the dragged element, which causes the dragged element to be dropped onto a non-droppable area.
How can I do this using jQuery Draggable and jQuery Droppable?
When the mouse is dragging a div element over a droppable area, pressing the ESC key should drag the element to an area that is not droppable
I´ve created a demo of a possible solution that you can check in plunker.
As stated by #ioneyed, you can select the dragged element directly using the selector .ui-draggable-dragging, which should be more efficient if you have lots of draggable elements.
The code used is the following, however, apparently it's not working in the snippet section. Use the fullscreen feature on the plunker or reproduce it locally.
var CANCELLED_CLASS = 'cancelled';
$(function() {
$(".draggable").draggable({
revert: function() {
// if element has the flag, remove the flag and revert the drop
if (this.hasClass(CANCELLED_CLASS)) {
this.removeClass(CANCELLED_CLASS);
return true;
}
return false;
}
});
$("#droppable").droppable();
});
function cancelDrag(e) {
if (e.keyCode != 27) return; // ESC = 27
$('.draggable') // get all draggable elements
.filter('.ui-draggable-dragging') // filter to remove the ones not being dragged
.addClass(CANCELLED_CLASS) // flag the element for a revert
.trigger('mouseup'); // trigger the mouseup to emulate the drop & force the revert
}
$(document).on('keyup', cancelDrag);
.draggable {
padding: 10px;
margin: 10px;
display: inline-block;
}
#droppable {
padding: 25px;
margin: 10px;
display: inline-block;
}
<div id="droppable" class="ui-widget-header">
<p>droppable</p>
</div>
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css">
I tried to help but without the expected result...
Searching on google you can find that while dragging other events are locked, similar behaviour to what happens during a window.alert...
By the way, I am on a Mac and I can capture all keyboard events but not "controls key such as command, ctrl, esc, ecc."
Hope help you as a starter point!
function DragAndDropCtrl($) {
var self = this;
self.ESC = 27;
self.draggables = $('.draggable');
self.dropArea = $('#droppable');
self.currentDraggingElement = null;
self.currentDismissed = false;
self.dismissDragging = function(event, eventManager) {
self.currentDismissed = true;
//Using the manager you can't use the revert function OMG!
//return eventManager.cancel();
};
self.dropArea.droppable();
self.draggables.draggable({
revert: function() {
var revert = self.currentDismissed;
self.currentDismissed = false;
console.log(revert, self.currentDismissed)
return revert;
},
start: function() {
self.currentDraggingElement = $(this);
},
end: function() {
self.currentDraggingElement = null;
}
});
$(document).keypress(function(event) {
console.log('key pressed', event)
//How to intercept the esc keypress?
self.dismissDragging(event, $.ui.ddmanager.current);
if(event.which === self.ESC || event.keyCode === self.ESC) {
self.dismissDragging(event, $.ui.ddmanager.current);
}
});
}
jQuery(document).ready(DragAndDropCtrl);
#droppable {
border: 1px solid #ddd;
background: lightseagreen;
text-align: center;
line-height: 200px;
margin: 1em .3em;
}
.draggable {
border: 1px solid #ddd;
display: inline-block;
width: 100%;
margin: .5em 0;
padding: 1em 2em;
cursor: move;
}
.sidebar { width: 30%; float: left; }
.main { width: 70%; float: right; }
* { box-sizing: border-box; }
<div class="sidebar">
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
<div class="ui-widget-content draggable">
<p>draggable</p>
</div>
</div>
<div class="main">
<div id="droppable" class="ui-widget-header">
<p>droppable</p>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css">
Related
How do I make this only fire :hover for the target element (ignoring the parents)?
Assume this is recursive design of object inside object, therefore with the same classes and an autogenerated id.
.group:hover {
background-color: red;
}
.group {
border: 1px solid black;
width: 100px;
padding: 20px;
}
<div id="g1" class="group">aaaa
<div id="g2" class="group">bbbb
<div id="g3" class="group">cccc
</div>
</div>
</div>
Since you tagged the question with javascript you can achieve this using it. The key is to use .stopProgagation() which will stop events from "falling through" down to your other elements.
See example below:
document.querySelectorAll(".group").forEach(elem => {
elem.addEventListener('mouseover', function(e) {
e.stopPropagation();
this.classList.add('group-hover');
});
elem.addEventListener('mouseout', function(e) {
this.classList.remove('group-hover');
});
});
.group-hover {
background-color: red;
}
.group {
border: 1px solid black;
width: 100px;
padding: 20px;
}
<div id="g1" class="group">aaaa
<div id="g2" class="group">bbbb
<div id="g3" class="group">cccc
</div>
</div>
</div>
Alternatively, you could intead use e.target to get the target of the event if you wish not to use stopPropagation():
document.querySelectorAll(".group").forEach(elem => {
elem.addEventListener('mouseover', e => e.target.classList.add('group-hover'));
elem.addEventListener('mouseout', e => e.target.classList.remove('group-hover'));
});
.group-hover {
background-color: red;
}
.group {
border: 1px solid black;
width: 100px;
padding: 20px;
}
<div id="g1" class="group">aaaa
<div id="g2" class="group">bbbb
<div id="g3" class="group">cccc
</div>
</div>
</div>
Only with JS, and using events delegate for simpler way
const All_g = document.querySelector('#g1');
All_g.onmouseover = function(event) {
let target = event.target;
target.style.background = 'red';
};
All_g.onmouseout = function(event) {
let target = event.target;
target.style.background = '';
};
.group {
border: 1px solid black;
width: 100px;
padding: 20px;
}
<div id="g1" class="group">aaaa
<div id="g2" class="group">bbbb
<div id="g3" class="group">cccc
</div>
</div>
</div>
some explanations :=> https://javascript.info/mousemove-mouseover-mouseout-mouseenter-mouseleave
You can do it in the following way:
var elements = document.getElementsByClassName('group');
var lastElement = null;
elements.each(element =>{
lastElement = element;
});
lastElement.on('hover', function(){
//do anything you wish with element
})
Approach 1
Register hover event to toggle class and use event.stopPropagation();
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
The bubbles read-only property of the Event interface indicates
whether the event bubbles up through the DOM or not.
https://developer.mozilla.org/en-US/docs/Web/API/Event/bubbles
Approach 2
Mouseenter event - By design it does not bubble - so don't have to perform event.stopPropagation()
Though similar to mouseover, it differs in that it doesn't bubble and
that it isn't sent to any descendants when the pointer is moved from
one of its descendants' physical space to its own physical space.
https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseenter_event
I know that jQuery draggable can accept a function for revert action.
$(".clipboard-li").draggable({
revert: function (event) {
console.log(event) // boolean value
}
});
But the parameter being passed to this function is a boolean.
How can I get the the element currently being dragged in this function?
revert is an option where you can set
Whether the element should revert to its start position when dragging stops
If you want to get the element after you drag it somewhere use stop event
$(".clipboard-li").draggable({
revert: function(event) {
return $(this).hasClass("revert"); //You can set it either to true or false
},
stop: function( event, ui ) {
console.log($(event.target).attr("class"));
}
});
.clipboard-li {
cursor: move;
width: 150px;
height: 150px;
border: 1px solid #000;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.min.js"></script>
<div class="container">
<div class="clipboard-li">
</div>
<div class="clipboard-li revert">
</div>
<div class="clipboard-li">
</div>
</div>
The revert handler function runs under the scope of the element being dragged; it's not passed in as an argument. As such you can use the this keyword to reference the element:
$('.drag').draggable({
revert: function() {
return this.prop('id') != 'allow';
}
})
.drag {
width: 75px;
height: 75px;
background-color: #CCC;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<div class="drag" id="allow">Allowed</div>
<div class="drag" id="deny">Denied</div>
I have a click event thats firing. It's working great and does what I need it to do. Here's the problem
The nature of the widget i'm building stacks elements on top of each other through position: absolute When i click on one of these stacked elements, only one event is firing, but id like every element to fire that is under the mouse cursor of the click. Is there a way to do this?
Please check the demo or run the code snippet in full page and click through all the divs to see the result message.
DEMO:
http://plnkr.co/edit/KRWvLmRhGbO200pFkOxL?p=preview
What I am doing here is :
Hide the top element
and
get the next absolute element's co-ordinate with document.elementFromPoint and then repeat.
Stack Snippet:
jQuery(document).ready(function(){
$common = $("div.common").on('click.passThrough', function (e, ee) {
var $element = $(this).hide();
try {
if (!ee) $("#output").empty();
$("<div/>").append('You have clicked on: '+$element.text()).appendTo($("#output"));
ee = ee || {
pageX: e.pageX,
pageY: e.pageY
};
var next = document.elementFromPoint(ee.pageX, ee.pageY);
next = (next.nodeType == 3) ? next.parentNode : next //Opera
$(next).trigger('click.passThrough', ee);
} catch (err) {
console.log("click.passThrough failed: " + err.message);
} finally {
$element.show();
}
});
$common.css({'backgroundColor':'rgba(0,0,0,0.2)'});
});
#output {
margin-bottom: 30px;
}
.common {
position: absolute;
height: 300px;
width: 300px;
padding: 3px;
border: 1px #000 solid;
}
.elem5 {
top: 150px;
left: 150px;
}
.elem4 {
top: 180px;
left: 180px;
}
.elem3 {
top: 210px;
left: 210px;
}
.elem2 {
top: 240px;
left: 240px;
}
.elem1 {
top: 270px;
left: 270px;
}
<script data-require="jquery#3.0.0" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
<div id="output"></div>
<div class="common elem1">Top Most Element</div>
<div class="common elem2">Element 2</div>
<div class="common elem3">Element 3</div>
<div class="common elem4">Element 4</div>
<div class="common elem5">Bottom Element</div>
Credit for source:
http://jsfiddle.net/E9zTs/2/
You can use customEvent property
Place all div in a parent div
add a click handler to the parent div
if there is a click in the parent box..determine whether the click is in any of the child boxes
If true. then send a click event to all child box
snippet
//This function changes the color of all child divs
function changeColor(e) {
this.style.background = "red";
}
//this function is attached to the parent div which will send that click event to all divs
function trigger(e) {
//create an event
event = new CustomEvent('click');
//if the event originates from a child div
if (e.target.className == 'box')
//loop through all child div
for (var i = 0; i < all_box.length; ++i) {
//dispatch a click event to each child div
all_box[i].dispatchEvent(event);
}
}
document.getElementById('parent').addEventListener('click', trigger)
var all_box = document.getElementsByClassName('box');
for (var i = 0; i < all_box.length; ++i) {
all_box[i].addEventListener('click', changeColor)
}
.box {
padding: 10px;
display: inline-block;
border: solid black;
}
#parent {
border: solid black;
padding: 10px;
}
;
<div id="parent">
<div class="box" id="primary">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
<div class="box">box3</div>
</div>
I am working on creating a website and I am stuck on a certain function I am trying to build. I am trying to slide back a div to its original place if anyplace outside the div is clicked. I've looked everywhere on stack but to no avail. What happens to me is that the background clicks remain active at all times, I only need it to be active when the div has slid to become sort of a popup.
Here is my jsfiddle: https://jsfiddle.net/DTcHh/10567/
Here is the jquery for one of the divs (the rest are similar)
var text = 1;
$('.login1').click(function(e){
e.preventDefault();
$('.loginform_hidden').toggleClass('loginform_visible');
$(".animateSlide").toggle(300, function(){
$(this).focus();
});
if(text == 1){
$(".div1").toggleClass("animateSlide col-xs-12");
$('.login1').html('Go Back');
$('.imageOne').toggleClass('animateSlideTop');
// If an event gets to the body
$('.div2, .div3, .patientAccess').toggle("fast");
document.addEventListener('mouseup', function(event){
var box = document.getElementsByClassName('animateSlide');
if (event.target != box && event.target.parentNode != box){
$('.div2, .div3, .patientAccess').toggle("fast");
$(".div1").toggleClass("animateSlide ");
text=0;
}
});
text = 0;
} else {
$(".div1").toggleClass("animateSlide");
$('.login1').html('Start Animation');
$('.imageOne').toggleClass('animateSlideTop');
$('.div2, .div3, .patientAccess').toggle("fast");
text = 1;
}
});
$(".div1").on('blur', function() {
$(this).fadeOut(300);
});
EDIT: The jsfiddle now incorporates what I have been trying to utilize.
As a demonstration, I built a simplified version of what I think you're aiming to achieve.
I'm using the "event.target" method described in this answer.
Since you are using CSS transitions, I'm using jQuery to detect the end of those transitions using a method found here.
I've given all boxes a class of "animbox" so that they can all be referenced as a group. I've also given each box its own ID so it can be styled individually with CSS.
I've commented the code in an attempt to explain what's going on.
// define all box elements
var $allBoxes = jQuery('.animbox');
// FUNCTION TO SHOW A SELECTED BOX
function showBox($thisBox) {
$allBoxes.hide(); // hide all boxes
$thisBox.show().addClass('animateSlide'); // show and animate selected box
$('div.login', $thisBox).text("Go Back"); // change the selected box's link text
}
// FUNCTION TO RETURN BOXES TO THE DEFAULT STATE
function restoreDefaultState() {
var $thisBox = jQuery('div.animbox.animateSlide'); // identify an open box
if ($thisBox.length) { // if a box is open...
$thisBox.removeClass('animateSlide'); // close this box
$thisBox.one('webkitTransitionEnd'+
' otransitionend'+
' oTransitionEnd'+
' msTransitionEnd'+
' transitionend', function(e) { // when the box is closed...
$allBoxes.show(); // show all boxes
$('div.login', $thisBox).text("Start Animation"); // change the link text
});
}
}
// CLICK HANDLER FOR ALL "login" TRIGGERS
$('div.login').click(function(e) {
var $thisBox = $(this).closest('div.animbox'); // identify clicked box
if (!$thisBox.hasClass('animateSlide')) { // if the box is not open...
showBox($thisBox); // open it
} else { // otherwise...
restoreDefaultState(); // restore the default state
}
});
// CLICK HANDLER TO RESTORE DEFAULT STATE WHEN CLICK HAPPENS OUTSIDE A BOX
$('body').click(function(evt) {
if ($(evt.target).hasClass('animbox') || // if a box is clicked...
$(evt.target).closest('div.animbox').length > 0) { // or a child of a box...
return; // cancel
}
restoreDefaultState(); // restore the default state
});
div.container-fluid {
background-color: #464646;
}
.v-center {
display: table;
height: 100vh;
}
.content {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.patientAccess {
transition: all .5s;
background: white;
height: 200px;
width: 90%;
position: absolute;
opacity: 0.7;
margin-top: -100px;
}
.patientAccess p {
font-size: 1.5em;
font-weight: bold;
}
div.animbox {
transition: all .5s;
position: absolute;
cursor: pointer;
width: 90%;
height: 100px;
opacity: 0.7;
}
div#animbox1 {
background: #e76700;
}
div#animbox2 {
background: #74b8fe;
}
div#animbox3 {
background: #848484;
}
div.login {
color: white;
font-size: 1em;
cursor: pointer;
}
div#animbox1.animateSlide {
width: 200px;
height: 300px;
margin-left: 100px;
opacity: 1;
}
div#animbox2.animateSlide {
width: 250px;
height: 450px;
margin-left: -25px;
margin-top: -150px;
}
div#animbox3.animateSlide {
width: 150px;
height: 150px;
opacity: .5;
margin-left: -100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<div class="container-fluid">
<div class="row-fluid">
<div class="col-xs-12 v-center">
<div class="content text-center">
<div class="col-xs-2 animated slideInRight "></div>
<div class="col-xs-2 animated slideInRight ">
<div class="patientAccess">
<p>Patient Resource Access</p>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox1">
<div class="login">Start Animation</div>
<div class="loginform_hidden "></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox2">
<div class="login">Start Animation</div>
<div class="registrationform_hidden"></div>
</div>
</div>
<div class="col-xs-2 animated slideInRight">
<div class="animbox" id="animbox3">
<div class="login">Start Animation</div>
</div>
</div>
</div>
</div>
</div>
</div>
You can namespace an event handler using this syntax:
$("#myElement").on("click.myEventHandlerName", function() { ... });
At any point, you can remove the event handler again by calling
$("#myElement").off("click.myEventHandlerName", "#myElement");
I'm using bxSlider, but I cannot focus a child element of my <ul> list. I want to focus a <div> or <li> within it. Below is a part of my HTML code:
<div class="bx-wrapper" style="max-width: 1308px; margin: 0px auto;">
<div class="bx-viewport" style="width: 100%; overflow: hidden; position: relative; height: 58px;">
<ul id="jalur" class="jalur" tabindex="21" style="width: 2715%; position: relative; transition-duration: 0s; transform: translate3d(-40px, 0px, 0px);">
<li id="lix1" style="float: left; list-style: outside none none; position: relative; width: 218px;">
<div class="fl">
<div id="e1" class="fl kurohige-prev jaman" data-time="00:30">00:30-01:00</div>
<div class="fl line-0"></div>
</div>
</li>
<li id="lix2" style="float: left; list-style: outside none none; position: relative; width: 218px;">
...
</ul>
</div>
I've tried to focus on the child <div>with id 'e1', but failed. Below is the related JavaScript code:
$(document).on( "keydown", function(event) {
var key = event.which;
console.log(key); //39-->right 37-->left, 38-->up 40-->down
if (key == '39') //success
{
var foc = $(':focus');
$(foc).next().focus();
console.log(foc);
}
else if (key == '37') //success
{
var foc = $(':focus');
$(foc).prev().focus();
console.log(foc);
}
else if (key == '40') //failed
{
$('#jalur li').first().focus();
var foc = $(':focus');
console.log(foc);
}
else if (key == '38') //failed
{
$('#jalur').children(":first").focus();
var foc = $(':focus');
console.log(foc);
}
});
However, using Firebug's command line I can go to any element:
$('#jalur li').first().focus();
This will give the following output:
Object[li#lix1]
I want to to get data-time="00:30" from the <div> and also focus it.
Focus won't work on <li> .
From jQuery Docs,
This event is implicitly applicable to a limited set of elements, such
as form elements (<input>, <select>, etc.) and links (<a href>).
Also I don't know what you want to achieve but,
You can do,
$('#jalur li').first().effect('highlight', {}, 1000);
DEMO