firefox bug - Options disappeared on hover - javascript

Firefox represents a bug when I insert a select box on mouseenter event. The whole dropdown list is gone on hover. How can I fix this bug?
document.querySelector('#test').addEventListener('mouseenter',function(){
this.innerHTML = '<select><option value=1>2</option><option value=2>3</option></select>';
});
#test{
width: 100px;
height: 100px;
background-color: #000;
}
<div id="test"></div>

Here is an alternative approach where we can append to the <div> element. In this example, mouseenter may fire a lot, so I wrapped this code in a closure to execute once to demo appending once. You can surely craft this to your needs but this approach should allow a bit more functionality than overwriting the html of the element
JSFiddle Link
var append = (function(ele, node) { // execute once closure
var executed = false;
return function (ele, node) {
if (!executed) {
executed = true;
ele.appendChild(node);
}
};
})();
document.querySelector('#test').addEventListener('mouseenter', function() {
var that = this;
var node = document.createElement('select');
node.innerHTML = '<option value=1>2</option><option value=2>3</option>'
append(that, node);
});

I can't select a value in Chrome either so this wouldn't be just a Firefox bug I think.
Anyway here is a fix. Just load the select when it's not loaded on mouse enter.
document.querySelector('#test').addEventListener('mouseenter',function(){
if(this.innerHTML===""){
this.innerHTML = '<select><option value=1>2</option><option value=2>3</option></select>';}
});

Related

Keep jQuery `Appended` Element Open When Hovering It

ALREADY ANSWERED MYSELF (See Answers)
So leading on from jQuery `[jQuery created Element].is(“:hover”)` Only Seems To Work In Chrome.
A bit more background:
I was trying to maintain hover when we moved from an element already in the DOM to an element added by jQuery's .append() method.
I was using .is(":hover"). This method was working fine in Chrome but no other browsers. As we found out (from the link above) it removed some time ago.
OLD :HOVER METHOD
var
hov = $("<div class=\"over\">I'm Over You</div>"),
box = $("<div>Result: WAITING</div>")
$("body").append(hov).append(box);
$("#MeHover").on('mouseleave', function(){
var d = new Date();
box.text("Result: " + hov.is(":hover").toString().toUpperCase() );
});
On the mouseleave listener, keep open if either the hovered or hoverer element are the relatedTarget
var $hovered = $('#MeHover');
var $hoverer = $("<div class=over>I'm Over You</div>");
$("body").append($hoverer);
$hovered.add($hoverer).mouseenter(function() {
$hoverer.fadeIn();
}).mouseleave(function(e) {
if (e.relatedTarget != $hoverer[0] && e.relatedTarget != $hovered[0])
$hoverer.fadeOut();
});
.over {
display: none;
position: absolute;
top: 20px;
left: 0;
right: 0;
background: green
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="MeHover">
Hover Over Me
</div>
So I toyed with tracking the mouse and seeing if it was in the container, but it seemed too expensive and complex to implement. In the end, I decided to go for the .data() route as per the below.
I also have a fiddle demonstrating: https://jsfiddle.net/glenn2223/uk7e7rwe/
CODE
var
hov = $("<div class=\"over\">I'm Over You</div>"),
box = $("<div>Result: WAITING</div>");
$("body").append(hov).append(box);
$("#MeHover").add(hov).mouseenter(function () {
$("#MeHover").data("keepHover", 1);
hov.fadeIn();
}).mouseleave(function () {
$("#MeHover").removeData("keepHover");
CloseHover();
});
function CloseHover(){
clearTimeout(t);
var t = setTimeout(function () {
if ($("#MeHover").data("keepHover") != 1)
hov.fadeOut();
}, 300);
}

JavaScript Submenu Not Persisting

I'm creating an additional tab on a menu dynamically (let's call this new tab, Watch), and all was going pretty well including the submenu that showed up once the new tab was hovered over. I looked at articles on event bubbling and took a look at other examples, but couldn't find a solution to my issue.
Whenever I hover over Watch, the submenu appears, but when I try to hover from Watch to its submenu, the submenu disappears. I need the submenu to persist when a user hovers over Watch or the submenu, and the submenu should only disappear once the user hovers out of either. Just to note, I cannot use CSS for my solution. I've attached my current code below with comments:
//PREPEND AS FIRST CHILD
var prependChild = function(parent, newFirstChild) {
parent.insertBefore(newFirstChild, parent.firstChild)
}
//DECLARING VARS
var navMenu = document.getElementsByClassName('navGlobal-list')[0];
categoryExplorer = document.getElementsByClassName('categoryExplorer')[0];
//CREATING NEW TAB
var exploreTab = document.createElement('li');
exploreTab.className = 'navGlobal-category';
//CREATING NEW SEARCH FORM
var searchHtml = ['<div class="searchProgram searchProgram--categoryExplorer">',
'<div class="searchProgram-container">',
'<input type="search" class="form-control form-control--light form-control--searchProgram" placeholder="Search programs" value="">',
'</div>',
'</div>'].join('');
//CREATING NEW WATCH CATEGORY EXPLORER CONTENT
var watchCategoryExplorerContent = document.createElement('div');
watchCategoryExplorerContent.className = 'categoryExplorer-content target-watch-content';
watchCategoryExplorerContent.innerHTML = searchHtml;
prependChild(categoryExplorer, watchCategoryExplorerContent)
var watchLink = document.createElement('a');
watchLink.setAttribute('href','/watch');
watchLink.innerHTML = 'watch'.toUpperCase();
exploreTab.appendChild(watchLink);
navMenu.appendChild(exploreTab); //ADDED 'WATCH' TO THE NAVIGATION
//CHANGE CLASSES ON HOVER
exploreTab.addEventListener("mouseover", function() {
exploreTab.className = 'navGlobal-category navGlobal-category--open';
categoryExplorer.className = 'categoryExplorer categoryExplorer--open';
watchCategoryExplorerContent.className = 'categoryExplorer-content categoryExplorer-content--open target-watch-content';
}, false);
exploreTab.addEventListener("mouseleave", function() {
exploreTab.className = 'navGlobal-category';
categoryExplorer.className = 'categoryExplorer';
watchCategoryExplorerContent.className = 'categoryExplorer-content target-watch-content';
}, false);
A potential (layout-dependent) way to keep the menu open would be to make it a child of the tab - that way, provided there is no space between the tab and the hover menu, you can hover from one to the other without creating a mouseleave event on the tab.
Another solution that is not layout-dependent would be to add some delay between the initial mouseleave event and the submenu closing. I've done something like this using jQuery before, but the same thing should be possible without it.
$('.navGlobal-category').mouseleave(function(){
setTimeout(
function(){
if(!isHovered($('.navGlobal-category')[0])){
exploreTab.className = 'navGlobal-category';
categoryExplorer.className = 'categoryExplorer';
watchCategoryExplorerContent.className = 'categoryExplorer-content target-watch-content';
}
}, 200);
});
function isHovered(e){
return ((e.parentNode.querySelector(":hover") ||
e.querySelector(":hover")) === e);
}
Credit to zb' for the isHovered solution: https://stackoverflow.com/a/14800287/5403341
For the non-layout solution #B1SeeMore suggests you don't actually need a delay.
Here is a working demo: https://jsfiddle.net/jw22ddzk/
<div id="one" class="menuitem"></div>
<div id="two" class="menuitem" style="display: none;"></div>
var elems = document.getElementsByClassName("menuitem");
for (var i = 0; i < elems.length; i += 1) {
elems[i].addEventListener("mouseleave", function () {
console.log("leave", this.id);
document.getElementById("two").style.display = "none";
});
elems[i].addEventListener("mouseenter", function () {
console.log("enter", this.id);
document.getElementById("two").style.display = "";
});
}
The trick is that mouseenter fires for two even if mouseleave hides the element. Just remember to show the element again. A likey explanation is that the mouseenter and mouseleave events spawn in pairs. So mouseenter happens regardless of the effects of mouseleave.
Note that this only works if the elements are beside eachother with pixel accuracy.
Another note: I notice that you're using mouseover and mouseleave. I wouldn't recommend doing that. There are two event pairs for detecting hovers: mouseenter/leave and mouseover/out. They are different events. They differ specifically in that mouseover/out will trigger also for child elments. My recommendation is that you don't interchange the pairs or you might get unexpected behaviour.

Prevent link dragging, but still allow text highlighting

I have some data in a table where clicking it will navigate you elsewhere, but people are requesting the ability to highlight the text to be able to copy/paste it elsewhere. Since they are links, the default behavior in HTML is to drag the link... I don't know why or how that is useful, but I want to disable that on certain links.
TL;DR: I want to be able to highlight the text of a link and not drag it.
The gif below should help explain my issue.
The following methods are NOT what I want:
I have seen examples that prevent both highlighting & dragging using something like this
<a draggable="false" href="#">
or this
.no-drag {
user-drag: none;
}
Or this
myElement.ondragstart = function () {
return false;
};
But obviously that is not what I need here.Is what I want possible to do?
In Google Chrome this works
user-select: none;
-webkit-user-drag: none;
#Julien Grégoire's answer above put me on the right track for this, but the below code is the basics of what I ended up using.
var clickedEl = document.getElementById("test");
var limit = 5;
var mouseMoved = false;
function resetEvents() {
clickedEl.onmousemove = null;
clickedEl.ondragstart = null;
clickedEl.onmouseleave = null;
mouseMoved = false;
}
clickedEl.onmousedown = function (downEvent) {
if (clickedEl.attributes.href) {
clickedEl.onclick = function (clickEvent) {
if (mouseMoved) {
clickEvent.preventDefault();
}
resetEvents();
};
}
clickedEl.onmouseleave = function () {
resetEvents();
};
clickedEl.onmousemove = function (moveEvent) {
// This prevents the text selection being dragged
clickedEl.ondragstart = function (dragEvent) {
dragEvent.preventDefault();
};
if (Math.abs(moveEvent.x - downEvent.x) >= limit || Math.abs(moveEvent.y - downEvent.y) >= limit) {
// If user clicks then moves the mouse within a certain limit, select the text inside
window.getSelection().selectAllChildren(clickedEl);
mouseMoved = true;
}
};
};
<a id="test" href="http://stackoverflow.com">Click or select</a>
I'm super late to answer but I'm just gonna leave it here:
Just put draggable="false" inside <a> tag,
<a draggable="false" href="./"></a>
then in CSS you put:
body {
-webkit-user-drag: none;
}
You could detect if user moves the mouse after the click and if so manage selection using window.getSelection. Something like this for example:
var linkEl = document.getElementById('test')
linkEl.onmousedown = function(downEvent) {
var clickedEl = downEvent.target;
var mouseMoved = false;
clickedEl.onmousemove = function() {
// If user clicks then moves, select the whole link
window.getSelection().selectAllChildren(clickedEl);
// Set a flag to prevent opening the link
mouseMoved = true;
// Reset mousemove, else it'll run constantly
clickedEl.onmousemove = null;
// This is only to prevent having the text selection being dragged
clickedEl.ondragstart = function(dragEvent) {
dragEvent.preventDefault();
}
}
if (mouseMoved) {
// If mouse has moved, prevent default
downEvent.preventDefault();
}
}
<a draggable="false" id="test" href="http://stackoverflow.com">Click or select</a>
This is the simplest solution that worked for me. You can change '*' to 'a'.
*, *::after, *::before {
-webkit-user-select: none;
-webkit-user-drag: none;
-webkit-app-region: no-drag;
}

script only firing on text link, not span

first post so go easy on my noobness!
I have a script that opens a popup window when some linked text is clicked, but now I want to get rid of the text and just use an empty span with background img as the link. Needless to say the script will not work with just the span and I'd appreciate some pointers on how to modify it to work (or suggest any workarounds if it ain't gonna work on an empty span).
Current link structure (which uses the text link to trigger the js window containing thelink.com):
<a href="http://thelink.com" class="pop">
<span class="icon_bg"><!-- empty span with image as background --></span>
some text here
</a>
Desired link structure (no text, just empty span with bg img):
<a href="http://thelink.com" class="pop">
<span class="icon_bg"><!-- empty span with image as background --></span>
</a>
Current script:
function popWin() {
function addEvent(element, eventName, callback) {
if (element.addEventListener) {
element.addEventListener(eventName, callback, false);
} else {
element.attachEvent("on" + eventName, callback);
}
}
function init() {
var links = document.querySelectorAll('a.pop');
    for (var i = 0; i < links.length; i++) {
popWin.addEvent(links[i], 'click', popWin.popup)
    }
}
function openPopup(e) {
var top = (screen.availHeight - 500) / 2;
var left = (screen.availWidth - 500) / 2;
var e = (e ? e : window.event);
    var target = (e.target ? e.target : e.srcElement);
var popup = window.open(
target.href,
'social',
'width=550,height=420,left='+ left +',top='+ top +',location=0,menubar=0,toolbar=0,status=0,scrollbars=1,resizable=1'
);
if(popup) {
popup.focus();
e.preventDefault();
return false;
}
return true;
}
return {
init: init,
popup: openPopup,
addEvent: addEvent
}}
var popWin = new popWin();
popWin.addEvent(window, 'load', popWin.init)
My hunch is to somehow define the span tag as the target using .nodeName. All help appreciated.
You can use the <span>&nbsp</span> to simulate invisible text and thus will cause the span to get width.
Your span is empty currently. Add some content to it, then it would work for you.
<span>Content</span>
Now the event would trigger for you.
Background image won't be visible until you have some width and height for the span. I would refer you to use
span {
/* change the display property of span; default is inline */
display: inline-block;
/* because width and height can be applied to only block level elements */
width: 100px;
height: 100px;
}
Now try it again. Have my fiddle, it makes a good use of your example, and it enables click on the textless span.
Also, you're not having any click handler in your code.
<span onclick="popWin()">
This would enable the click event.
http://jsfiddle.net/afzaal_ahmad_zeeshan/FdjZy/
OK, I think I've worked out the solution, but am curious if this is gonna be bombproof (seems to work in the few browsers I've tried so far).
Changed the line:
var target = (e.target ? e.target : e.srcElement)
To:
var target = (e.target ? e.target : e.srcElement).parentNode;
Now the span tag is triggering the script without the need for any text anywhere within the a tags.

Changing parent css on child focus (without breaking parent:hover css rules)

I made a menu on html (on the side and 100% heigth, expandeable as in android holo)
<div id="menu">
<button class="menubutton"></button>
<button class="menubutton"></button>
</div>
The menu normally remains transparent and with a short width:
#menu {
background-color: transparent;
width: 8%;
}
The idea was to expand and color it on hover. It was easy:
#menu:hover {
background-color: blue;
width: 90%;
}
There is no problem untill here. I need the same effect on focus. There is no way in css to change parent css on child focus (neither hover by the way, but it is not needed, cuase i can use the entire menu hover).
So i used a script:
var menubuttonfocus = document.getElementsByClassName("menubutton");
for (i=0; i<menubuttonfocus.length; i++) {
menubuttonfocus[i].addEventListener("focus", function() {
menu.style.backgroundColor = "blue";
menu.style.width = "90%";
});
menubuttonfocus[i].addEventListener("blur", function() {
menu.style.backgroundColor = "transparent";
menu.style.width = "8%";
});
}
The script works just fine, the problem is that when you trigger those events by focusing a button, the css of #menu:hover changes somehow and #menu does not change when hovering. I tried to solve this by doing something similar but with hover instead of focus:
menu.addEventListener("mouseenter", function(){
menu.style.backgroundColor = "blue";
menu.style.width = "90%";
});
menu.addEventListener("mouseout", function(){
menu.style.backgroundColor = "transparent";
menu.style.width = "8%";
});
This works somehow, but it is REALLY buggy.
I tried also to select "#menu:hover,#menu:focus", but it doesn't work because the focus is on the button elements and not in #menu.
Please avoid jquery if posible, and i know it's asking for too much but a pure css solution would be awesome.
Probably helpful info: html element are created dinamically with javascript.
I can show more code or screenshot, you can even download it (it is a chrome app) if needed: chrome webstore page
Thanks.
SOLVED: I did what #GCyrillus told me, changing #menu class on focus via javascript eventListener. .buttonbeingfocused contains the same css as "#menu:hover". Here is the script:
var menubuttonfocus = document.getElementsByClassName("menubutton");
for (i=0; i<menubuttonfocus.length; i++) {
menubuttonfocus[i].addEventListener("focus", function() {
menu.classList.add("buttonbeingfocused");
});
menubuttonfocus[i].addEventListener("blur", function() {
menu.classList.remove("buttonbeingfocused");
});
}
if the problem is what I think it is - you forgetting about one thing:
When you focusing / mouseentering the .menubutton - you are mouseleaving #menu and vice-versa - so your menu behaviour is unpredictible because you want to show your menu and hide it at the same time.
solution is usually setting some timeout before running "hiding" part of the script, and clearing this timeout (if exist) when running "showing" part.
it will be something like this:
var menuTimeout;
function showMenu() {
if (menuTimeout) clearTimeout(menuTimeout);
menu.style.backgroundColor = "blue";
menu.style.width = "90%";
}
function hideMenu() {
menuTimeout = setTimeout( function() {
menu.style.backgroundColor = "transparent";
menu.style.width = "8%";
}, 800);
}
//then add your listeners like you did - but put these functions as a handlers - like this:
menu.addEventListener("mouseenter", showMenu);
...
//in addition you need also "mouseenter" and "mouseleave" events handled on .menubuttons

Categories