I'm using this code to switch background when hovering an element and pressing the shift key. It works if I hold the shift key down before I enter the element but not if I'm already on the element and pressing the shift key. Ideas? Thanks!
var shiftPressed = null;
$(document).on({
keydown: function (e) {
if( e.shiftKey )
{
shiftPressed = true;
}
},
keyup: function (e) {
shiftPressed = false;
}
});
$('div').on({
mousemove: function (e) {
if( shiftPressed )
{
$(this).css('backgroundColor', 'red');
}
else
{
$(this).css('backgroundColor', '');
}
},
mouseover: function (e) {
if( shiftPressed )
{
$(this).css('backgroundColor', 'red');
}
else
{
$(this).css('backgroundColor', '');
}
},
mouseleave: function (e) {
$(this).css('backgroundColor', '');
}
}, 'span');
div {
position:absolut;
width:100px;
height:100px;
background:#999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span>TARGET</span>
</div>
A div cannot be focused (by default); thus, it cannot capture key presses.
However, if you bind the keypress event listener to the document, the event will fire on every key press. Keep the mouseover and mouseleave bound to the div, because they can be fired with a non-focusable element.
Also, a keyboard event is different than a mouse event, so you can't access shiftKey of e in mouseover. Instead, I would use the && operator to test if both conditions are met: the shift key and the mouse in, storing whether the shift key is pressed in a boolean and checking that on mouseover / mouseleave.
var shiftPressed = null; // global data
$(document).on('keyup keydown', function(e) {
shiftPressed = e.shiftKey;
updateDivs();
});
$('div').on({
mouseover: function(e) {
$(this).data('hovered', true); // element-specific data
updateDiv(this);
},
mouseleave: function(e) {
$(this).data('hovered', false); // element-specific data
updateDiv(this);
}
});
function updateDiv(div) {
if (shiftPressed && $(div).data('hovered'))
$(div).css('backgroundColor', 'red');
else
$(div).css('backgroundColor', '');
}
/** updates all divs in document */
function updateDivs() {
$('div').each(function() {
updateDiv(this);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Hello world</div>
<div>Hi world</div>
You can add a bunch of code to listen to the mouse position and also an event for the keydown and figure out where the cursor is...
There might be a better solution, but this works.
$('div').on("mouseenter", "span", function(e) {
if (e.shiftKey) {
$(this).css('backgroundColor', 'red');
}
}).on("mouseleave", "span", function(e) {
$(this).css('backgroundColor', 'white');
})
let x = 0;
let y = 0;
$(document).on("mousemove", function(e) {
x = e.clientX;
y = e.clientY;
}).on("keydown keyup", function(e) {
$(document.elementFromPoint(x, y)).trigger({
type: e.type==="keydown" ? "mouseenter" : "mouseleave",
shiftKey: true
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
</div>
Other way is to set an active element and not worry about the x and y position.
let active;
$('div').on("mouseenter", "span", function(e) {
active = this;
if (e.shiftKey) {
$(this).css('backgroundColor', 'red');
}
}).on("mouseleave", "span", function(e) {
console.log(e)
$(this).css('backgroundColor', 'white');
if (active && !e.custTrigger && $(this).is(active)) active = null
})
$(document).on("keydown keyup", function(e) {
if (active) {
$(active).trigger({
type: e.type==="keydown" ?"mouseenter" : "mouseleave",
shiftKey: true,
custTrigger: true
})
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
<span>Test</span>
</div>
This is a bit sloppy but it should work. Just set some vars and then check them whenever an event is fired.
N.B. you have to click once inside the iframe to make it work (so that it can capture keypresses). Presumably on your page you're not using an iframe, so that won't be necessary.
Array.prototype.forEach.call(document.querySelectorAll('.box'), box => {
let hover = false;
let shift = false;
box.addEventListener('mouseenter', ev => {
hover = true;
check();
});
box.addEventListener('mouseleave', ev => {
hover = false;
check();
});
document.addEventListener('keydown', ev => {
shift = ev.shiftKey;
check();
});
document.addEventListener('keyup', ev => {
shift = ev.shiftKey;
check();
});
function check() {
box.style.backgroundColor = shift && hover ? 'red' : '';
}
});
div {
width: 100px;
height: 100px;
background: #999;
margin: 5px;
display: inline-block;
}
<div class="box">
<span>TARGET</span>
</div>
<div class="box">
<span>TARGET</span>
</div>
<div class="box">
<span>TARGET</span>
</div>
A little late to the party, but here's a non jquery example that monitors keystrokes and adds the various shift/ctrl/alt states to the html classList in real time.
css can respond accordingly.
note
to test this code in the stackoverflow snippet, focus is required because the snippet runs in an iframe.
when running as a top level page, the current document is focused by default.
first click "Run Code Snippet" and the select the iframe directly below it - click on the word "shift", and you will be focused in the iframe
you can then tap the shift key.
const html = document.querySelector("html");
["keyup","keydown"].forEach(function(ev){
document.addEventListener(ev,updateHtmlKeyClasses);
});
function updateHtmlKeyClasses(e){
["shiftKey","ctrlKey","altKey"].forEach(function(shiftKey){
html.classList[e[shiftKey]?"add":"remove"](shiftKey);
});
}
div {
margin :10px;
}
html.shiftKey .shiftstate,
html.ctrlKey .ctrlstate,
html.altKey .altstate {
background:lime;
}
.test {
background:cyan;
}
.test:hover {
background:yellow;
}
html.shiftKey .test:hover {
background:red;
}
<div class="shiftstate">
shift
</div>
<div class="ctrlstate">
ctrl
</div>
<div class="altstate">
alt
</div>
<div class="test">
TEST AREA
</div>
keypress doesn't capture the shift-key
This [the keypress event] is similar to the keydown event, except that modifier and non-printing keys such as Shift, Esc, and delete trigger keydown events but not keypress events.
Related
I have callback button and hidden callback form.
Form shows up after click on button and hide after click on any place on the screen except the form-space.
BUT! Form don't hide on mobile devices. I think that problem is in touch tracking on iOS.
How can i fix this problem?
function showcallbackform (objName) {
if ( $(objName).css('display') == 'none' ) {
$(objName).animate({height: 'show'}, 200);
} else {
$(objName).animate({height: 'hide'}, 200);
}
};
jQuery(function($){
$(document).mouseup(function (e){
var div = $("#callback-form");
if (!div.is(e.target)
&& div.has(e.target).length === 0) {
div.hide();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can bind both actions (mouse and touch events) like this:
jQuery(function($){
$(document).bind( "mouseup touchend", function(e){
var div = $("#callback-form");
if (!div.is(e.target)
&& div.has(e.target).length === 0) {
div.hide();
}
});
});
Hi I have multiple divs on the page. I want to raise an alert based on a user hovering over one of the divs and pressing control z. I need to in effect alert out what is in the span dependant upon which div the user is hovered over on.
I have tried with getbyId the problem arises with multiple elements. I am unsure if i need to bind every element.
<div class="mydiv">Keypress here!<span>test</span></div>
<div class="mydiv">Keypress here!<span>test1</span></div>
var pressed = false;
onload = function(e) {
var myElement = document.getElementsByTagName('div');
function keyaction(e, element) {
// var originator = e.target || e.srcElement;
if (e.charCode === 122 && e.ctrlKey) {
//myElement.innerHTML += String.fromCharCode(e.charCode);
alert(true);
}
}
for (var i = 0; i < myElement.length; i++) {
myElement[i].addEventListener("mouseover", function (e)
{
document.addEventListener("keypress", function(t){keyaction(t,e);}, false);
});
myElement[i].addEventListener("mouseout", function ()
{
document.removeEventListener("keypress", keyaction, false);
});
}
}
I think you are overdoing for what is needed. A simple keydown event bind on mouseover and unbind on mouseout would do the trick.
Here's an example :
<div id="wrapper">
<div class="mydiv">Keypress here!<span>test</span></div>
<div class="mydiv">Keypress here!<span>test1</span></div>
</div>
<br>
Keys Pressed :
<br>
<div id="key"></div>
$("#wrapper .mydiv").on("mouseover",function()
{
$(document).bind("keydown",function(e) {
var originator = e.keyCode || e.which;
if(e.ctrlKey)
$("#key").append(originator + ",");
});
}).on("mouseout",function()
{
$(document).unbind("keydown");
});
http://jsfiddle.net/s095evxh/2/
P.S : for some reason , Jsfiddle doesn't allow keydown event on mouseover so you might have to click manually on the div to make it work but the solution works flawless on a local system.
I would suggest that you use the normalized e.which if available. You also have code 122 which is F11 keys code not 90 related to the 'z' key.
Turn the event manager on when over and off when not per your stated desire:
$('.mydiv').on('mouseenter', function () {
$(window).on('keydown', function (e) {
var code = e.which ||e.keyCode;
$('#status').append('we:'+ code);
if (code === 90 && e.ctrlKey) {
$('#status').append('howdy');
}
});
});
$('.mydiv').on('mouseleave', function () {
$(window).off('keydown');
});
Note that I changed to post some text to a fictitious "status" div rather than your alert as that will change where the cursor hovers. Change that to some real action. There MAY be issues with the event bubbling but I will leave that determination to you.
Here is a key code list (google for more/another) https://gist.github.com/lbj96347/2567917
EDIT: simple update to push the span text into the status div:
<div class="mydiv">Keypress here!<span>test</span>
</div>
<div class="mydiv">Keypress here!<span>test1</span>
</div>
<div id="status">empty
<div>
$('.mydiv').on('mouseenter', function () {
var me = this;
$(window).on('keydown', function (e) {
var code = e.which || e.keyCode;
$('#status').append('we:' + code);
if (code === 90 && e.ctrlKey) {
$('#status').append($(me).find('span').text());
}
});
});
$('.mydiv').on('mouseleave', function () {
$(window).off('keydown');
$('#status').text('out');
});
Listen for the keypress on the window and add mouse events to the elements to toggle a variable with what element is active.
var activeElem = null;
$(".mydiv")
.on("mouseenter", function () {
activeElem = $(this);
}).on("mouseleave", function () {
if(activeElem && activeElem.is(this)) {
activeElem = null;
}
});
$(window).on("keydown", function (evt) {
if( activeElem && evt.keyCode===90 && evt.ctrlKey) {
console.log(activeElem.find("span").text());
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mydiv">Keypress here!<span>test</span></div>
<div class="mydiv">Keypress here!<span>test1</span></div>
To prevent frequent binding/unbinding of the "keydown" handler whenever the user hovers over the <div>, I would simply keep track of the <div> currently being hovered. Something like this:
var hovering = null;
$(document)
.on('keydown', function(e) {
if (e.which === 90 && e.ctrlKey && hovering) {
console.log($('span', hovering).text());
}
})
.on('mouseover', '.mydiv', function(e) {
hovering = this;
})
.on('mouseout', '.mydiv', function() {
hovering = null;
});
.mydiv:hover {
cursor: pointer;
color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mydiv">Test <span>1</span></div>
<div class="mydiv">Test <span>2</span></div>
<div class="mydiv">Test <span>3</span></div>
<div class="mydiv">Test <span>4</span></div>
<div class="mydiv">Test <span>5</span></div>
I would propose the other way around. Listen for the keypress, and select the element which has the hover.
$(document).keypress(function(e) {
if (e.charCode === 26 && e.ctrlKey) {
console.log("Key pressed");
console.log($('.mydiv:hover span').html());
}
});
Codepen Demo
If I am understanding your question correctly, you are looking for the text value of the span within the hovered element. Traversing the DOM from $(this) will get you what you want.
$(".mydiv").mouseover(function (e) {
alert($(this).find('span').text());
});
Using Chrome, Tampermonkey and jQuery - I would like to discover and remove key event bindings on a third party website.
I have tried to bind (over them) and prevent propagation using:
,_cancel:function(e){
//console.log('keyProcessed');
e.cancelBubble = true; // IE4+
try {
e.keyCode = 0;
} catch (e) {
} // IE5
if (window.event) {e.returnValue = false; } // IE6
if (e.preventDefault) {e.preventDefault(); } // moz/opera/konqueror
if (e.stopPropagation) {e.stopPropagation(); } // all
return false;
}
... but the key still fires.
I have tried enumerating elements with jQuery:
$('*').each(function(){
if(this.onkeydown){
console.log(this.tagName,this.onkeydown);
}
});
... which gives no results for keydown keyup or keypress
I have also tried
$('*').unbind();
How can I enumerate and kill bindings?
Edit, Updated
Before click at button , default action at input element is to input text ; following click at button , evt.preventDefault() called , text prevented from being input at element.
Try
var events = ["keydown", "keyup", "keypress"];
$.each($("*"), function (index, elem) {
if ($._data(elem, "events") != undefined) {
// check `elem` for `keydown`, `keyup`, `keypress` `events`
if (new RegExp(events.join("|")).test(
Object.keys($._data(elem, "events")))) {
$.each(events, function (key, val) {
// do stuff at `value` having `events`
// call `evt.preventDefault` at `elem`
// having `keydown`, `keyup`, `keypress` `events` `events`
$(elem).on(val, function(evt) {
evt.preventDefault()
})
})
}
};
});
$(function () {
$("input:eq(0)").on("keyup", function (e) {
console.log(e);
});
$("input:eq(1)").on("keydown", function (e) {
console.log(e);
});
$("input:eq(2)").on("keypress", function (e) {
console.log(e);
});
$("button").on("click", function() {
var events = ["keydown", "keyup", "keypress"];
$.each($("*"), function (index, elem) {
if ($._data(elem, "events") != undefined) {
if (new RegExp(events.join("|")).test(
Object.keys($._data(elem, "events")))) {
$.each(events, function (key, val) {
$(elem).on(val, function(evt) {
evt.preventDefault()
})
})
}
};
});
})
})
input:nth-of-type(1) {
width : 50px;
height : 50px;
background : blue;
}
input:nth-of-type(2) {
display : block;
width : 50px;
height : 50px;
background : yellow;
}
input:nth-of-type(3) {
display : block;
width : 50px;
height : 50px;
background : orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button>click to remove keydown, keyup, keypress events below</button><br />
<input type="text" />
<input type="text" />
<input type="text" />
Couldn't find a solution that actually worked, but I want that on a click, a div shows.
Now this works when I load the page, but then after that first click, I have to click twice every time for the div to show.
Any ideas?
$(document).ready(function () {
setMenu();
});
function setMenu()
{
var headerExtIsOpen = false;
$('#headerExt').hide();
$('#header').click(function () {
if (!headerExtIsOpen) {
$('#headerExt').show();
headerExtIsOpen = true;
} else {
$('#headerExt').hide();
headerExtIsOpen = false;
}
});
}
There is no need to remember the state, just use toggle()
$(function () {
setMenu();
});
function setMenu()
{
$('#headerExt').hide();
$('#header').on("click", function (e) {
e.preventDefault();
$('#headerExt').toggle();
});
}
You said you want to toggle other things.
Best thing would be to toggle a class to change the color
$('#header').on("click", function (e) {
e.preventDefault();
$(this).toggleClass("open");
$('#headerExt').toggle();
});
another way is to check the state
$('#header').on("click", function (e) {
e.preventDefault();
var child = $('#headerExt').toggle();
var isOpen = child.is(":visibile");
$(this).css("background-color" : isOpen ? "red" : "blue" );
});
if the layout is something like
<div class="portlet">
<h2>Header</h2>
<div>
<p>Content</p>
</div>
</div>
You can have CSS like this
.portlet h2 { background-color: yellow; }
.portlet > div { display: none; }
.portlet.open h2 { background-color: green; }
.portlet.open > div { display: block; }
And the JavaScript
$(".portlet h2 a").on("click", function() {
$(this).closest(".portlet").toggleClass("open");
});
And there is layouts where it would be possible to have zero JavaScript involved.
Turns out I had some script hidden in my .js file that closes the menu again when the user clicks elsewhere, that I forgot about.
function resetMenu(e) {
var container = $('#headerExt');
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
$('#header').css("background-color", "inherit");
container.hide();
headerExtIsOpen = false;
}
}
I forgot to set the headerExtIsOpen back to false again after closing it in this function (code above shows the fix). Now it works fine :)
Is there any way to disable onclick events from firing for events on a particular z-index, besides running through all elements and setting their onclick to function(){} if they are on that z-index?
Edit:
At this point, the best I can come up with is to hook each function in the DOM tree recursively:
function preventZIndexClicks(elem) {
// ensure not a text node
if(!elem.popupflag) { elem.popupflag = 1;
if(elem.onclick) { var temp = elem.onclick;
elem.onclick = function(e) {
if(g_threshold > elem.style.zIndex)
return;
temp(e);}
}
}
// Call recusively on elem.childNodes
}
Of course, then I would have to deal with the rather annoying IE issues with setting custom properties on DOM elements...
You could check the z-index in the event and let it bubble through the rest.
function onclick(e) {
if(this.style.zIndex == 10) return;
//do stuff
}
EDIT:
Just to clarify how i mean, consider this:
<div id="div1" style="background-color: red;width:100px;height:100px;z-index:1">
<div id="div2" style="background-color: green;width:50px;height:50px;z-index:2">
<div id="div3" style="background-color: blue;width:25px;height:25px;z-index:3">
</div>
</div>
</div>
With this javascript:
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
bind(div1,"click",click);
bind(div2,"click",click);
bind(div3,"click",click);
function click(e) {
if(this.style.zIndex == 2) return;
alert(this.style.backgroundColor);
}
function bind(element,event,callback){
var onevent="on"+event;
if(element.addEventListener)
element.addEventListener(event,callback,false);
else if(element.attachEvent)
element.attachEvent(onevent,callback);
else{
var e=element[onevent];
element[onevent]=function(){
var h=e.apply(this,arguments),cbk=callback.apply(this,arguments);
return h==undefined?cbk:(cbk==undefined?h:cbk&&h);
}
}
}
Now, the click will work as follow:
click red: -> alert "red"
click green: -> alert "red"
click blue: -> alert "blue" -> alert "red"
As you see the green element with z-index:2; will not "fire" the event
What about something like:
<script type="text/javascript">
window.onclick = function(e)
{
var targetElem;
if (!e)
{
var e = window.event;
}
if (e.target)
{
targetElem = e.target;
}
else if (e.srcElement)
{
targetElem = e.srcElement;
}
if (targetElem.nodeType == document.TEXT_NODE)
{
targetElem = targetElem.parentNode;
}
if (targetElem.style.zIndex == 100)
{
// do stuff
}
};
</script>
with jQuery:
$('*').each(function() {
var $this = $(this);
if ($this.css('z-index') < g_threshold) {
$this.unbind('click'); //unbinds all click handlers from a DOM element
$this.click(function(e) {
e.stopPropagation();
});
}
});
this is basically like what you do, but requires no additional attributes or whatever else you dislike. If you need to leave, say, textbox untouched, then use $('*').not('input:text')