Cancel :active element styling - javascript

I have DOM elements with :active CSS styling. If a user makes a click, but never releases the click, I want to be able to cancel the :active styling through Javascript.
I have tried doing document.activeElement.blur() but that doesn't work when the user does not release the click. (See fiddle here.)
How can I force blur an element if the user doesn't release their click?

#bobdye's example doesn't work because <div> elements aren't "focusable" by default.
You can force this behaviour by assigning a tabindex property to the div, here is a fiddle.
HTML
<div class="defocus">.::.:.:.::.</div>
<div class="defocus">:..:.:.:..:</div>
<div class="defocus">.::.:.:.::.</div>
You add the class="defocus" attribute to any element that needs to blur after x seconds.
CSS (relevant)
div:active {
color:lightcoral;
}
JavaScript
(function () {
window.addEventListener("load", function () {
var seconds = 0.15 * 1000;
var defocused = document.getElementsByClassName("defocus");
for (var i = 0, l = defocused.length; i < l; i++) {
var el = defocused[i];
el.style.outline = 0; //optional
el.setAttribute("tabindex", -1);
el.addEventListener("mousedown", blur);
}
function blur(e) {
var el = e.target;
setTimeout(function (el) {
el.blur();
}, seconds, el);
}
});
})();
First we wrap this function in a seaf just as a commodity (it will prevent the blur function and variables from being accessible).
Then we get all the elements with a defocus class.
Then we iterate over them.
First we eliminate the focus outline some browsers use because it looks ugly in a div, but it's up to you.
Then we set a tabindex="-1". Using -1 as an index prevents it from acting as a tab break point but allows it to recieve focus and blur events.
Finally we add the blur() function to the mousedown event which will defocus de element after x seconds.
Then we define the blur() function which will take care of defocusing the element with a setTimeout().
That's it, hope it helps!
Note: I don't particularly care for the bounty, keep your rep!
Note: Thanks to #Adam for pointing out that seaf's variables need the var prefix to prevent them from being global.

This Fiddle a simple example of canceling the active state if the user holds the mouse down for more than 500ms.
It uses a link:
<a id="testlink" href="#">Click this</a>
styled to be red if active, and this Javascript:
var lnk = document.getElementById('testlink');
var mousedown = false;
var timerId = null;
lnk.addEventListener('mousedown', function(e) {
mousedown = true;
timerId = window.setTimeout(function() {
if (mousedown) {
lnk.blur();
}
}, 500);
});
lnk.addEventListener('click', function(e) {
mousedown = false;
window.clearTimeout(timerId);
});
Obviously not customized for your particular case, but a "proof of concept".

to be added to other answers, you may use a transition (delayed or not):http://codepen.io/anon/pen/LEXZGB
*:active {
background: red;
filter:blur(5px);
transition: filter 3s 1s;
}
<script src='http://s.codepen.io/assets/libs/prefixfree.min.js'></script>
see me blured if you click too long.

Related

How do I dispatch a mousedown/click event on the window in JavaScript? [duplicate]

I want a function that tells me which element the mouse cursor is over.
So, for example, if the user's mouse is over this textarea (with id wmd-input), calling window.which_element_is_the_mouse_on() will be functionally equivalent to $("#wmd-input").
DEMO
There's a really cool function called document.elementFromPoint which does what it sounds like.
What we need is to find the x and y coords of the mouse and then call it using those values:
document.addEventListener('mousemove', e => {
console.clear()
console.log( document.elementFromPoint(e.clientX, e.clientY) )
}, {passive: true})
[class^='level']{
width: 100px;
height: 100px;
padding: 15px;
background: #00000033;
}
<div class='level-1'>
<div class='level-2'>
<div class='level-3'>
Hover
</div>
</div>
</div>
document.elementFromPoint
jQuery event object
In newer browsers, you could do the following:
document.querySelectorAll( ":hover" );
That'll give you a NodeList of items that the mouse is currently over in document order. The last element in the NodeList is the most specific, each preceding one should be a parent, grandparent, and so on.
Although the following may not actually answering the question, since this is the first result of googling (the googler may not asking exactly the same question:), hope it will provide some extra input.
There are actually two different approaches to get a list of all elements the mouse is currently over (for newer browsers, perhaps):
The "structural" approach - Ascending DOM tree
As in dherman's answer, one can call
var elements = document.querySelectorAll(':hover');
However, this assumes that only children will overlay their ancestors, which is usually the case, but not true in general, especially when dealing with SVG where element in different branches of the DOM tree may overlap each other.
The "visual" approach - Based on "visual" overlapping
This method uses document.elementFromPoint(x, y) to find the topmost element, temporarily hide it (since we recover it immediately in the same context, the browser will not actually renders this), then go on to find the second topmost element... Looks a little hacky, but it returns what you expect when there are, e.g., siblings elements in a tree occluding each other. Please find this post for more details,
function allElementsFromPoint(x, y) {
var element, elements = [];
var old_visibility = [];
while (true) {
element = document.elementFromPoint(x, y);
if (!element || element === document.documentElement) {
break;
}
elements.push(element);
old_visibility.push(element.style.visibility);
element.style.visibility = 'hidden'; // Temporarily hide the element (without changing the layout)
}
for (var k = 0; k < elements.length; k++) {
elements[k].style.visibility = old_visibility[k];
}
elements.reverse();
return elements;
}
Try both, and check their different returns.
elementFromPoint() gets only the first element in DOM tree. This is mostly not enough for developers needs. To get more than one element at e.g. the current mouse pointer position, this is the function you need:
document.elementsFromPoint(x, y) . // Mind the 's' in elements
This returns an array of all element objects under the given point.
Just pass the mouse X and Y values to this function.
More information is here: DocumentOrShadowRoot.elementsFromPoint()
For very old browsers which are not supported, you may use this answer as a fallback.
The following code will help you to get the element of the mouse pointer. The resulted elements will display in the console.
document.addEventListener('mousemove', function(e) {
console.log(document.elementFromPoint(e.pageX, e.pageY));
})
Mouseover events bubble, so you can put a single listener on the body and wait for them to bubble up, then grab the event.target or event.srcElement:
function getTarget(event) {
var el = event.target || event.srcElement;
return el.nodeType == 1? el : el.parentNode;
}
<body onmouseover="doSomething(getTarget(event));">
You can look at the target of the mouseover event on some suitable ancestor:
var currentElement = null;
document.addEventListener('mouseover', function (e) {
currentElement = e.target;
});
Here’s a demo.
Demo :D
Move your mouse in the snippet window :D
<script>
document.addEventListener('mouseover', function (e) {
console.log ("You are in ", e.target.tagName);
});
</script>
<!-- One simple solution to your problem could be like this: -->
<div>
<input type="text" id="fname" onmousemove="javascript: alert(this.id);" />
<!-- OR -->
<input type="text" id="fname" onclick="javascript: alert(this.id);" />
</div>
<!-- Both mousemove over the field & click on the field displays "fname"-->
<!-- Works fantastic in IE, FireFox, Chrome, Opera. -->
<!-- I didn't test it for Safari. -->
You can use this selector to undermouse object and then manipulate it as a jQuery object:
$(':hover').last();
2022 Update:
document.elementsFromPoint() (Note the 's' in elements) is compatible with all major browsers. It basically does the same thing that elementFrompoint does, but retrieves all the elements in DOM order.
Mozilla has a good example of this:
HTML
<div>
<p>Some text</p>
</div>
<p>Elements at point 30, 20:</p>
<div id="output"></div>
JavaScript
let output = document.getElementById("output");
if (document.elementsFromPoint) {
let elements = document.elementsFromPoint(30, 20);
for (var i = 0; i < elements.length; i++) {
output.textContent += elements[i].localName;
if (i < elements.length - 1) {
output.textContent += " < ";
}
}
} else {
output.innerHTML = "<span style=\"color: red;\">" +
"Browser does not support <code>document.elementsFromPoint()</code>" +
"</span>";
}
Output
Some text
Elements at point 30, 20:
p < div < body < html
https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint
The target of the mousemove DOM event is the top-most DOM element under the cursor when the mouse moves:
(function(){
//Don't fire multiple times in a row for the same element
var prevTarget=null;
document.addEventListener('mousemove', function(e) {
//This will be the top-most DOM element under cursor
var target=e.target;
if(target!==prevTarget){
console.log(target);
prevTarget=target;
}
});
})();
This is similar to #Philip Walton's solution, but doesn't require jQuery or a setInterval.
Here's a solution for those that may still be struggling. You want to add a mouseover event on the 'parent' element of the child element(s) you want detected. The below code shows you how to go about it.
const wrapper = document.getElementById('wrapper') //parent element
const position = document.getElementById("displaySelection")
wrapper.addEventListener('mousemove', function(e) {
let elementPointed = document.elementFromPoint(e.clientX, e.clientY)
console.log(elementPointed)
});
Demo on CodePen
Let me start out by saying that I don't recommend using the method I'm about to suggest. It's much better to use event driven development and bind events only to the elements you're interested in knowing whether or not the mouse is over with mouseover, mouseout, mouseenter, mouseleave, etc.
If you absolutely must have the ability to know which element the mouse is over, you'd need to write a function that binds the mouseover event to everything in the DOM, and then store whatever the current element is in some variable.
You could so something like this:
window.which_element_is_the_mouse_on = (function() {
var currentElement;
$("body *").on('mouseover', function(e) {
if(e.target === e.currentTarget) {
currentElement = this;
}
});
return function() {
console.log(currentElement);
}
}());
Basically, I've created an immediate function which sets the event on all elements and stores the current element within the closure to minimize your footprint.
Here's a working demo that calls window.which_element_is_the_mouse_on every second and logs what element the mouse is currently over to the console.
http://jsfiddle.net/LWFpJ/1/

javascript eventlistener on multiple objects

I made an EventListener for a few <div> elements, now i want do change the opacity on a child of this specific element to change if the EventListener is true on this specific element. How do I write that with jQuery or Javascript? I already wrote the pseudoquote, which I think should work. I have a problem to translate it to js.
var overLay = document.getElementsByClassName("overlay");
for (i = 0; i < overLay.length; i++) {
overLay[i].addEventListener("mouseover", mouseOver);
overLay[i].addEventListener("mouseout", mouseOut);
}
function mouseOver() {
document.getElementById("project_07").style.maxWidth = "20px"; //just for testing works!
/* PSEUDOCODE
if overlay[i] (mouseover === true) {
getChildElement of (this/ overlay[i]) // is an <img> element
and .style.opacity = ".8";
*/
}
function mouseOut() {
document.getElementById("project_07").style.maxWidth = "100%";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
With event listeners, you can use this to reference the current element. Because the handler will only react when during a mouseover event, you don't need to check it because it will always be true.
function mouseOver() {
this.querySelector("img").style.opacity = 0.8;
}
Then, if you want to clear the style change on mouseout, just add the same code to your mouseOut function.
function mouseOut() {
this.querySelector("img").style.opacity = 1;
}
Also, if you are only modifying the style of child elements, you could solve this with just css.
.overlay:hover img {
opacity: .8;
}
When event is fired you can access the event prameters. It goes to function as n attribute.
One of properties of the event is target - element that fireв event.
function mouseOver(e) {
e.target.querySelector('img').style.maxWidth = "20px";
}
Try to console.dir(e.target) and research it.
I will simply suggest:
1.assign class to all divs you want to have child change opacity
let's say myClass
$('.myClass').children().on('mouseenter', function(){
$(this).css('opacity', '0.8');
});

onclick of button from paginated load not triggering

I have a procedural feed within my website which loads in data every time the user scrolls to the bottom of the page; the usual stuff.
The pagination itself works fine; however, the clicking of buttons which utilize JavaScript do not work. At all.
This is the JavaScript trigger for the buttons which is not working:
var modalTrigger = document.querySelectorAll(".ts-modal__trigger"), // the buttons
modal;
document.onclick = function(e){ // document on click
for(var i = 0; i < modalTrigger.length; i++){ // iterate through each button
if(e.target == modalTrigger[i]){ // if target clicked was button
e.stopPropagation(); // stop dom event from bubbling
modal = document.getElementById(modalTrigger[i].getAttribute("data-activemodal"));
document.body.style.overflow = "hidden"; // disable scroll on page
modal.style.display = "block"; // display modal
}
}
}
As far as I'm aware, this should be working (with the use of stopPropagation()), but alas, it does not.
I was going to use Inline JS, but I feel like it's extremely unnecessary and could be done it just a couple of lines of separate JavaScript, instead of adding extra HTML into the mix for no reason.
So any, and all help is appreciated,
Thanks. :)
Fiddle: https://jsfiddle.net/xhp4cesr/
EDIT: I noticed that after removing the span within the button, it would work, but as soon as it was added back, it would not.
One way you can do this is to remove e.stopPropogation and also target the children
var modalTrigger = document.querySelectorAll(".ts-modal__trigger"), // the buttons
modal;
document.onclick = function(e) { // document on click
for (var i = 0; i < modalTrigger.length; i++) { // iterate through each button
if (e.target == modalTrigger[i] || modalTrigger[i].children) { /* <- added children as target */
modal = modalTrigger[i].getAttribute("data-activemodal");
console.log(modal);
}
}
}
a {
background: red;
padding: 40px;
}
span {
color: yellow;
}
<a class="ts-modal__trigger" data-activemodal="ts-main-feed_status-comments-overlay">
<span>11</span>
</a>

getElement 1 and do1, getElement 2 and do2, getElement 3 and do3

I have this code for smooth scrolling, it works great but only for one "clickme" id, how could i use this code for multiple tabs whit i++
<div class="navbar">
<button type="button" id="clickme1">Scroll to red section!</button>
<button type="button" id="clickme2">Scroll to blue section!</button>
</div>
<div class="second" id="second">Hello</div>
<div class="tab1" id="tab1">The start of the red section!</div>
<div class="tab2" id="tab2">The start of the blue section!</div>
and here is the pure javascript that i want to use, please do not recommend me jQuery and anchor navigation.
document.getElementById('clickme1').addEventListener('click', function() {
var header = document.querySelectorAll('.navbar');
aim = -header[0].clientHeight;
initial = Date.now();
smoothScroll(document.getElementById('tab1'));
});
*******or more simplified, how can i make this code shorter:*******
document.getElementById('clickme1').addEventListener('click', function() {
var header = document.querySelectorAll('.navbar');
aim = -header[0].clientHeight;
initial = Date.now();
smoothScroll(document.getElementById('tab1'));
});
document.getElementById('clickme2').addEventListener('click', function() {
var header = document.querySelectorAll('.navbar');
aim = -header[0].clientHeight;
initial = Date.now();
smoothScroll(document.getElementById('tab2'));
});
here is JSFIDDLE
You can do something like following
// Get buttons
var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
// Iterate over buttons and add handler
buttons[i].addEventListener('click', clickHandler, false);
}
// Handler function
function clickHandler(){
var counter = this.id.substring(7); // Substring id to get counter
var header = document.querySelectorAll('.navbar');
aim = -header[0].clientHeight;
initial = Date.now();
smoothScroll(document.getElementById('tab'+counter));
}
Note : As you can have some other buttons on your page and do not want to add this handler to them, so, in place of tag name selector, I will suggest you to add a specific class to the button elements and then use class selector to get elements.
You should consider using proper anchor links with progressive enhancement for smooth scrolling. This would involve either changing the buttons to <a> tags or just wrapping them:
<div class="navbar">
<button type="button">Scroll to red section!</button>
<button type="button">Scroll to blue section!</button>
</div>
You can then use event delegation to trap clicks on any anchor link at the document level:
document.addEventListener('click', function (evt) {
var tgt = evt.target;
if (tgt.tagName === 'A' && tgt.getAttribute('href')[0] === '#') {
smoothScroll(document.getElementById(tgt.hash.slice(1)));
}
});
There are numerous benefits to this approach, including:
Ability to hotlink to a section by copy/pasting the URL
Graceful degrading when JavaScript is not present.

Clicking with element on other element

I know it sounds silly, but what I want to do is trigger click with some html element hovering over another element.
Lets say we got .cursor that is hovering anchor text. In this case click on .cursor should open a google page.
<div class="cursor"></div>
<div class="htmlPage">
Google
Faccebook
Stack
</div>
Any ideas how to do that?
and this don't count
$('.cursor').click(function(){
$('.htmlPage a').click();
})
Cursor should be movable and should be able to click on other links.
Cursor is that blue circle hovering Google button.
Here I have cursor on google, now on click this should link to google, If i were to click on stack then stack should have opened.
If you are not using IE you can use pointer-events:none in CSS. Then your element will be unresponsive to any mouse interaction (and acting like a ghost foreground element).
The workaround for IE is someting like that:
var x = event.pageX;
var y = event.pageY;
$('.cursor').hide();
var here = document.elementFromPoint(x, y);
$('.cursor').show();
// Do what you want with the element here
// Find the parent a element needed with here.parentNode and here.tagName === "A"
// And then fire the click function
I've never use jQuery but I think it should work.
Hope it could help
you can try to get the ".cursor" position on click and compare to each ".htmlPage a" positions and change the window.location.href with the one of the element that overlaps
$(".cursor").click(function(){
var cursor=$(this);
var cl = cursor.offset().left;
var cr = cl+cursor.width();
var ct = cursor.offset().top;
var cb = ct+cursor.height();
$(".htmlPage a").each(function(){
var page=$(this);
var pl = page.offset().left;
var pr = pl+page.width();
var pt = page.offset().top;
var pb = pt+page.height();
if(((cl>pl&&cl<pr)||(cr>pl&&cr<pr))&&((ct>pt&&ct<pb)||(cb>pt&&cb<pb))){
window.location.href=page.attr("href");
}
});
}).draggable();
http://jsfiddle.net/EUmeB/
$('.cursor').click(function(){
$('.htmlPage a').click();
})
Attach an event handler to the cursor class.
$('.cursor').on('click',function()
{
window.location.href = $(this).siblings('.htmlPage').attr('href');
}
This gets the sibling of the element and makes the location equal to that sibling
To be a little more explicit, this might be best.
$('.cursor').click(function(){
$(this).next().children('a').click();
});
Try this:
Demo
// Target link in the next div, following div.cursor
$("div.cursor").click(function() {
var link = $(this).next(".htmlPage").children("a").attr("href");
window.location.href = link;
});

Categories

Resources