Disable hover when key pressed - javascript

I implement a custom dropdown, and I have a problem when I move by keyboard: hover works too and I don't know how to disable it. I've paste my code here http://jsfiddle.net/4o0bcv1d/, but here my code works correct. When I copy code to index.html - hover works again, when I move by keyboard.
How I can fix it?
var doc = document;
var keydown_count = -1;
var dropdown_content = doc.querySelector('.dropdown-content');
var dropdown_items = doc.querySelectorAll('.dropdown-item');
var dropdown_items_length = dropdown_items.length;
var clear_navigation_hover = function () {
for (var i = 0; i < dropdown_items_length; ++i) {
dropdown_items[i].classList.remove('dropdown-item--hover');
};
}
var navigation_hover_by_keydown = function (event) {
var event = event || event.window;
var UP = 38;
var DOWN = 40;
var SCROLL_STEP = 66;
if (event.keyCode === UP) {
keydown_count--;
if (keydown_count < 0) {
keydown_count = dropdown_items_length - 1;
dropdown_content.scrollTop = 66 * dropdown_items_length;
}
if (keydown_count < (dropdown_items_length - 3)) {
dropdown_content.scrollTop -= 66;
};
} else if (event.keyCode === DOWN) {
keydown_count++;
if (keydown_count >= dropdown_items_length) {
keydown_count = 0;
dropdown_content.scrollTop = 0;
}
if (keydown_count > 3) {
dropdown_content.scrollTop += 66;
};
}
clear_navigation_hover();
dropdown_items[keydown_count].classList.add('dropdown-item--hover');
}
var dropdown_input = doc.querySelector('.dropdown-input');
dropdown_input.addEventListener('keydown', navigation_hover_by_keydown, false);
var navigation_hover_by_hover = function () {
clear_navigation_hover();
this.classList.add('dropdown-item--hover');
keydown_count = this.getAttribute('data-index');
console.log('hover');
}
for (var i = 0; i < dropdown_items_length; ++i) {
dropdown_items[i].addEventListener('mouseover', navigation_hover_by_hover, false);
}

You can use the CSS pointer-events feature to disable hovering on any of the page element. On keypress you need to add this attribute to the body tag like this
document.body.style.pointerEvents = 'none';
and again on key release you could remove this property so that mouse over starts working again. So at key release you need to do
document.body.style.pointerEvents = 'auto';
The pointer-events property allows to exclude an HTML element from being a mouse target. All the descendant elements are also excluded from being a mouse target unless the pointer-events property has been explicitly overridden for that node.

you can set the css selector, instead :hover, anything like :hover:not(.unhover), the class .unhover can be added using js

Related

Is there a way to add a CSS class to a DOM element while dragging the cursor and mouse click pressed?

I'm trying to create a pathfinder visualizer. So far I have created a 16x45 grid with the following function:
export const drawBoard = () => {
const boardContainer: HTMLDivElement | null = document.querySelector(
".board-container"
);
if (boardContainer != null) {
// 16x45 board
for (let i = 0; i < 16; i++) {
const row = document.createElement("div");
row.classList.add("row");
for (let j = 0; j < 45; j++) {
const col = document.createElement("col");
col.classList.add("col");
col.setAttribute("data-row", `${i}`);
col.setAttribute("data-col", `${j}`);
row.appendChild(col);
col.addEventListener("click", function () {
this.classList.add("wall"); // Add a wall class to the CSS
});
}
boardContainer.appendChild(row);
}
}
};
This function generates the following grid in my document:
I can get the x and y position of a specific tile, as seen here:
I've added click events to all this tiles. So that when I click a tile a wall CSS class is added to that tile and fills it with black color.
My question is the following:
Is there a way to add the CSS wall class to the tiles while the mouse is pressed? Is there a special event listener for this?
This is what I want to achieve:
You need to keep track whether or not the mouse is down, and listen for mousemove. Something like this should work:
//stores whether or not the mouse is down
let mouseDown = false;
document.addEventListener("mousedown" () => mouseDown = true);
document.addEventListener("mouseup" () => mouseDown = false);
export const drawBoard = () => {
const boardContainer: HTMLDivElement | null = document.querySelector(
".board-container"
);
if (boardContainer != null) {
// 16x45 board
for (let i = 0; i < 16; i++) {
const row = document.createElement("div");
row.classList.add("row");
for (let j = 0; j < 45; j++) {
const col = document.createElement("col");
col.classList.add("col");
col.setAttribute("data-row", `${i}`);
col.setAttribute("data-col", `${j}`);
row.appendChild(col);
//added mousemove listener
col.addEventListener("mousemove", function() {
//if mouse is down add class
mouseDown && this.classList.add("wall")
});
col.addEventListener("click", function() {
//do not need to check for mousedown
this.classList.add("wall")
});
}
boardContainer.appendChild(row);
}
}
};
You can use the mousedown event to achieve what you're looking for. There's also a corresponding mouseup event as well.
Here's a reference of all events as well.
https://developer.mozilla.org/en-US/docs/Web/Events

Access nesting elements

I use multiple buttons with a common class. When the user clicks on any of the buttons, I want to make elements with another class fill in red.
So basically I want to color everything inside .wrapper that has the .col class.
This is what I have so far.
var clickMe = document.querySelectorAll('.common');
for (var i = 0; i < clickMe.length; i++) {
clickMe[i].addEventListener('click', function (event) {
var x = document.querySelectorAll('#wrapper svg .col'); //this is where my issue starts.
x.style.fill = "red";
}, false);
}
Looking for a pure javascript solution.
Something like following should work for you:
var clickMe = document.querySelectorAll('.common');
for (var i = 0; i < clickMe.length; i++) {
clickMe[i].addEventListener('click', function (event) {
var x = document.querySelectorAll('#wrapper svg .col'); //this is where my issue starts.
for(var j=0;j<x.length;j++){
x[j].style.fill = "red";
}
}, false);
}

getElementByTagName(a) for autoscroll

What I have now is:
var a = document.getElementsByTagName('a');
I use this to get all elements with an 'a' and when I scroll it autoscrolls to the next 'a' element.
The problem with that is that I also use links (that use an a href="") so sometimes it scrolls to a link instead of an <a name="name"></a>. Is their anyway to fix this? Like:
var a = document.getElementsByTagName('a name=""');
(this one doesnt work)
If full code is needed I will add it below, but its probably not needed.
(function () {
var delay = false;
$(document).on('mousewheel DOMMouseScroll', function (event) {
event.preventDefault();
if (delay) return;
delay = true;
setTimeout(function () {
delay = false
}, 800);
var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;
var a = document.getElementsByTagName('a');
if (wd < 0) {
for (var i = 0; i < a.length; i++) {
var t = a[i].getClientRects()[0].top;
if (t >= window.innerHeight * 0.95) break;
}
}
else {
for (var i = a.length - 1; i >= 0; i--) {
var t = a[i].getClientRects()[0].top;
if (t < -window.innerHeight * 0.5) break;
}
}
$('html,body').animate({
scrollTop: a[i].offsetTop
}, 800);
});
})();
You can use QuerySelector for HTML 5 supporting browsers .You can check its support from http://caniuse.com/#feat=queryselector
QuerySelectorAll
document.querySelectorAll("a[name='<setname>']");
For older browsers use Jquery
$("a[name='<setname>']")
If you don't want to set a specific name just leave it blank. The selector is same for both JQuery and HTML 5 querySelector
document.querySelectorAll("a[name]");
or
$("a[name]")
Try with querySelectorAll()
document.querySelectorAll("a[name='examplename']");
find a empty
document.querySelectorAll("a[name='']");

Scrolling button jQuery doesn't work instantly

I'm working on some web pages that use a button to scroll to the next div. I can get it to work on every page, except in this particular instance (see jsfiddle).
My problem is that the buttons don't work on loading the page, the user first has to start scrolling manually, before the buttons work. I'm assuming that's because of some fault in my jQuery coding, which I've looked over and over, but I can't seem to find the problem. Is there anyone who is a bit more familiar with jQuery than I am who can offer me a solution?
http://jsfiddle.net/y5wx7nst/3/
$(document).ready(function () {
var currentElement = $("#bodytext > div:nth-child(1)");
var onScroll = function () {
var container = $("#bodytext");
var children = $(".section");
for (var i = 0; i < children.length; i++) {
var child = $(children[i]);
var childLeft = container.offset().left < child.offset().left;
if (childLeft) {
currentElement = child;
console.log(currentElement);
return;
}
}
};
var scrollToElement = function ($element) {
var container = $("#bodytext");
var children = $(".section");
var width = 0;
for (var i = 0; i < children.length; i++) {
var child = $(children[i]);
if (child.get(0) == $element.get(0)) {
if (i === 0) {
width = 0;
}
container.animate({
scrollLeft: width
}, 500);
onScroll();
}
if (child.next().length > 0) {
width += child.next().offset().left - child.offset().left;
} else {
width += child.width();
}
}
};
var buttonright = function (e) {
scrollToElement(currentElement.next());
};
var buttonleft = function (e) {
var container = $("#bodytext");
if (currentElement.prev().length > 0) {
if (container.offset().left == currentElement.prev().offset().left) {
currentElement = currentElement.prev().prev().length > 0 ? currentElement.prev().prev() : currentElement.prev();
} else {
currentElement = currentElement.prev();
}
}
scrollToElement(currentElement);
};
$("#bodytext").scroll(onScroll);
$("#buttonright").click(buttonright);
$("#buttonleft").click(buttonleft);
});
You are only calling the onScroll() function after you initially scroll:
$("#bodytext").scroll(onScroll);
I added this before that declaration and it all worked:
onScroll();
jsfiddle: http://jsfiddle.net/y5wx7nst/5/
When code run value of currentElement is not correct. So you should calculate it calling a function onScroll();
...
$("#bodytext").scroll(onScroll);
$("#buttonright").click(buttonright);
$("#buttonleft").click(buttonleft);
onScroll();
});

Using labels like HTML5 placeholder

I am trying to use <label> elements in my html contact form like the HTML5 placeholder attribute for inputs. I have written the following JavaScript to to act as a reusable function witch will provide the following functionality.
Find the input by name.
Get the value of the input.
Find the label belonging to the input.
Change the label style depending on the state of the input.
Change the label style depending on the value of the input.
However it is not working and I don't know why as no errors appear in the console. What am I doing wrong? here is a JS Fiddle with code
function placeholder(field_name) {
// Get the input box with field_name
// Then get input value
var box = document.getElementsByName(field_name);
var i;
for (i = 0; i < box.length; i++) {
var value = document.getElementById(box[i].value);
}
// Get the labels belonging to each box using the HTML for attribute
var labels = document.getElementsByTagName('LABEL');
for (i = 0; i < labels.length; i++) {
if (labels[i].htmlFor !== '') {
var elem = document.getElementById(labels[i].htmlFor);
if (elem) {
box.label = labels[i];
}
}
}
// Colors
var focusColor = "#D5D5D5";
var blurColor = "#B3B3B3";
// If no text is in the box then show the label grey color
box.onblur = function () {
box.label.style.color = blurColor;
};
// If input focuses change label color to light grey
box.onfocus = function () {
box.label.style.color = focusColor;
};
// If there is text in the box then hide the label
if (box.value !== "") {
// Quick do something, hide!
box.label.style.color = "transparent";
}
}
// Call the function passing field names as parameters
placeholder(document.getElementsByName("email"));
placeholder(document.getElementsByName("firstName"));
placeholder(document.getElementsByName("lastName"));
This might be considered a little overkill on the number of listeners I've used, feel free to remove any you think unnecessary, but I've tried to employ your HTML structure as you have it and give you all desired effects. It should work for either the <label>s for matching the <input>s id OR matching it's <name> (given no id matches). I'll always say prefer using an id over name. I believe this JavaScript should also work in all browsers too, except the addEventListener for which you'd need a shim for old IE versions (let me know if it doesn't in one/the error message).
Demo
var focusColor = "#D5D5D5", blurColor = "#B3B3B3";
function placeholder(fieldName) {
var named = document.getElementsByName(fieldName), i;
for (i = 0; i < named.length; ++i) { // loop over all elements with this name
(function (n) { // catch in scope
var labels = [], tmp, j, fn, focus, blur;
if ('labels' in n && n.labels.length > 0) labels = n.labels; // if labels provided by browser use it
else { // get labels from form, filter to ones we want
tmp = n.form.getElementsByTagName('label');
for (j = 0;j < tmp.length; ++j) {
if (tmp[j].htmlFor === fieldName) {
labels.push(tmp[j]);
}
}
}
for (j = 0; j < labels.length; ++j) { // loop over each label
(function (label) { // catch label in scope
fn = function () {
if (this.value === '') {
label.style.visibility = 'visible';
} else {
label.style.visibility = 'hidden';
}
};
focus = function () {
label.style.color = focusColor;
};
blur = function () {
label.style.color = blurColor;
};
}(labels[j]));
n.addEventListener('click', fn); // add to relevant listeners
n.addEventListener('keydown', fn);
n.addEventListener('keypress', fn);
n.addEventListener('keyup', fn);
n.addEventListener('focus', fn);
n.addEventListener('focus', focus);
n.addEventListener('blur', fn);
n.addEventListener('blur', blur);
}
}(named[i]));
}
};
placeholder("email"); // just pass the name attribute
placeholder("firstName");
placeholder("lastName");
http://jsfiddle.net/cCxjk/5/
var inputs = document.getElementsByTagName('input');
var old_ele = '';
var old_label ='';
function hide_label(ele){
var id_of_input = ele.target.id;
var label = document.getElementById(id_of_input + '-placeholder');
if(ele.target == document.activeElement){
label.style.display = 'none';
}
if (old_ele.value == '' && old_ele != document.activeElement){
old_label.style.display = 'inline';
}
old_ele = ele.target;
old_label = label;
}
for(var i = 0; i < inputs.length; i++){
inputs[i].addEventListener('click', hide_label);
}
I will point out a couple things, you will have to find away around the fact that the label is inside the input so users now can't click on half of the input and actually have the input gain focus.
Also I guess you want to do this in IE (otherwise I would strongly advise using the html5 placeholder!) which means you would need to change the ele.target to ele.srcElement.

Categories