Any way to prevent "deselection" of highlighted text? - javascript

Highlight some text on this webpage, then click basically anywhere on the document. Your selection will disappear.
Is there a way to prevent this behavior when the user clicks on a specific element, either by CSS or Javascript?
E.g.:
var element = document.getElementById("foo");
foo.onclick = function(e){
//some magic here that prevents deselection from occuring
}
or
foo.style.preventDeselect = "true";
Edit: Perhaps I could store the selection, then after "mouseclick" restore the selection? Is there a way to store aselection, and then reselect it?
Thanks!

"return false" as well as "e.preventDefault()" in onmousedown works in FF and Safari, but not IE. The only solution for IE, as far as I can tell, is to throw an error.
This works in all browsers (but causes an error in IE, since preventDefault is not a method):
//clicking the 'test' element will not deselect text.
var test = document.getElementById("test");
test.onmousedown = function(e){
e = e || window.event;
e.preventDefault();
}
I'd still like to do this error-free in IE, if possible
Thanks to Paolo Bergantino for the the "onmousedown" tip.

This works for me on Firefox, haven't tried IE though. Try clicking on the foo.style.preventDeselect = "true"; line when you have text selected. Uses the mousedown event.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<script>
$(document).ready(function() {
$('#test').mousedown(function() {
return false;
});
});
</script>
<body>
Highlight some text on this webpage, then click basically anywhere on the document. Your selection will disappear.<br><Br>
Is there a way to prevent this behavior when the user clicks on a specific element, either by CSS or Javascript?<br><Br>
E.g.:<br><Br>
var element = document.getElementById("foo");<br>
foo.onclick = function(e){<br>
//some magic here that prevents deselection from occuring<br>
}<br><Br>
or<br><Br>
<span id='test'>foo.style.preventDeselect = "true";</span><br><Br>
Thanks!<br><Br>
</body>
</html>

This behavior, while mostly universal in modern browsers, is browser/implementation specific and almost completely unrelated to CSS or Javascript. In particular, note that Firefox maintains separate selection states for the page at large and the contents of text boxes, while IE does not do this. Even worse, consider text-mode browsers with separate mouse and keyboard selection interfaces.

What about
if(e.preventDefault)
e.preventDefault();
else
e.returnValue = false;

Just in case somebody checks this out, I had a similar problem. I needed to run some javascript on a piece of selected text that was fired by clicking on a toolbar button (span with background-image). I solved my problem by changing the spans to anchors with an href of "javascript:void(0)". That prevented my selected text from being deselected.

the best way that I figured out how to do this is, for IE you need to setup a listener on 'onselectstart'. For Mozilla and other browsers you can do on 'mousedown'. This will only work, if you don't use 'mousedown' in any other portion of your site!
Snippet:
YUI way:
FF browser:
YAHOO.util.Event.addListener(window,
'mousedown', function(evt) {
YAHOO.util.Event.preventDefault(evt);
});
IE Browser:
In IE you are not allowed to set this listener on window, since in IE it doesn't work.
best thing to do is on your body element set a class element, then reference it, and apply
the listener to that element object.
// Get the element by class and
assign to var bar
YAHOO.util.Event.addListener(bar,
'selectstart', function(evt) {
YAHOO.util.Event.preventDefault(evt);
});
if you want to do it the easy way, just do
window.onMouseDown = function()
{return false;}
or for IE
body.onSelectStart = function()
{return false;}
Hope this helps.

Related

Create onchange event with javascript in Firefox

I've been working on trying to trigger an onchange listener with java script in Mozilla Firefox. I've found a lot on Stack Overflow posted about this, but nothing seems to be working for my unique case.
I've created this HTML with a onchange listener from an onchange event using this helpful post (JavaScript OnChange Listener position in HTML markup). Here's my code:
<HTML>
<head>
<script type="text/javascript">
window.onload= function () {
if(window.addEventListener) {
document.getElementsByClassName('search-box')[0].addEventListener('change', loadXMLDoc, false);
} else if (window.attachEvent){
document.getElementsByClassName('search-box')[0].attachEvent("onchange", loadXMLDoc);
}
function loadXMLDoc(){
alert('It worked');
}
}
function addTextCallListener() {
var searchBox = document.getElementsByClassName("search-box")[0];
searchBox.value = "Hello";
}
</script>
</head>
<BODY>
<input type="text" class="search-box" placeholder="Player Search">
<br \>
<button type="button" onclick="addTextCallListener()">Click Me!</button>
</BODY>
</HTML>
I also saved it as this jsfiddle (for some reason I had to keep it all together for it to work, I couldn't break it up into js and html).
https://jsfiddle.net/josephfedor42/crogL0zd/1/
If you play with this jsfiddle you can see that entering text and pressing enter will trigger the listener and the pop up with the message “It worked” will appear.
But if the button “Click Me!” is pressed it only changes the value of the text box, and the onchange listener is not called.
I realize I could easily add an onchange event to this button. But I want to to trigger the listener by programatically/ superficially using javascript in my addTextCallListener() function.
I've tried the simple stuff, like calling
searchBox.onchange();
searchBox.focus();
searchBox.click();
And a combination of these to add and remove the focus. But it doesn't seem to work. I've found quite a few posts on triggering an onchange event, but nothing that works in Firefox.
Any help would be appreciated.
Thanks for that link of a possible duplicated question. I had checked out that link before.
But I gave it a try again. I saved the jsfiddle from them both and neither one work.
My implementation of Dorian's answer
https://jsfiddle.net/josephfedor42/zaakd3dj/
My implementation of Alsciende's answer
https://jsfiddle.net/josephfedor42/xhs6L6u2/
emphasize mine
According to the mdn page about the change event,
The change event is fired for <input>, <select>, and <textarea>
elements when a change to the element's value is committed by the
user.
and to whatwg specs :
When the input and change events apply (which is the case for all
input controls other than buttons and those with the type attribute in
the Hidden state), the events are fired to indicate that the user has
interacted with the control.
Therefore, setting the value of an input is not an action "committed by the user" nor a sign that "the user has interacted with the control", since it was made by the code.
So, even if the specifications for this event are kind of unclear, the event should not fire when you change its value by code.
Something like this should work:
function addTextCallListener() {
var searchBox = document.getElementsByClassName("search-box")[0];
searchBox.value = "Hello";
//fire the event
if (document.createEvent) {
searchBox.dispatchEvent('change');
} else {
searchBox.fireEvent("onchange");
}
}
Here is the code I needed to add to my function addTextCallListener:
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent( 'change', true, true );
searchBox.dispatchEvent(evObj);
I updated the jsfiddle. The working code is here https://jsfiddle.net/josephfedor42/crogL0zd/7/
Replace onchange with change in this part:
document.getElementsByClassName('search-box')[0].attachEvent("onchange", loadXMLDoc);

Keeping an iPad keyboard up between inputs

Right now I'm using a bit of jQuery to hide the iPad keyboard when an input loses focus.
jQuery(function($) {
$(document).on('touchend', function(e) {
document.activeElement.blur();
});
});
However during a process like the checkout when a user clicks from input to input the keyboard disappears and the reappears every time the input is changed. Is there any way to change the above jquery code to where it only blurs the active element if the place on the document that is touched does NOT have an input type of text?
Well, I haven't tried this with iPad before, so I'm not sure that it will work, but you can check the type of document.activeElement to determine if it is a text or textarea field. If it isn't, then perform your blur(). The code would be like this:
jQuery(function($) {
$(document).on('touchend', function(e) {
setTimeout(function() {
var currentElement = document.activeElement;
if ($(currentElement).not("textarea, :text").length > 0) {
currentElement.blur();
}
}, 100);
});
});
The setTimeout is needed to make sure that the focus has transferred to the next element, before checking what the current element is (doing it immediately, will return the <body> as the activeElement).
This general approach (i.e., identifying what type the current activeElement is) works in a desktop browser environment, and it SHOULD work on an iPad, but, like I said earlier, I've not had a chance to test it there, so this is more of a "possible solution" than an actual "answer", until you give it a try and se if it works for you. :D

How can tell I which element i clicked on to trigger a blur event handler? [duplicate]

This question already has answers here:
When a 'blur' event occurs, how can I find out which element focus went *to*?
(23 answers)
Closed 8 years ago.
Quite simple. I have a blur() event handler that fires a function, I want the function not to fire when the blur is triggered by the click on a certain element.
I tried document.activeElement but i get a HTMLBodyElement instead of the element I click on.
code:
$j(".input_filtrare_camp").blur(
function(event) {
nr_img = this.parentNode.id.split("_")[1];
//alert(document.activeElement);
if(document.activeElement.id.indexOf("img_exact") < 0) //run only if the id of the element I clicked on doesn't contain "img_exact"
enter_input_filtrare(event.target);
});
the alert is for troubleshooting, of course.
I used techfoobar's solution as follows:
var currElem = null;
$(document).mousedown(function(e) {
currElem = e.target;
});
$j(".input_filtrare_camp").blur(
function(event) {
nr_img = this.parentNode.id.split("_")[1];
if(currElem.id.indexOf("img_exact") < 0) //run only if the id of the element I clicked on doesn't contain "img_exact"
enter_input_filtrare(event.target);
});
Check out PointedEars' answer for some important information regarding this issue.
The following code will tell you where focus went to, it requires a setTimeout, because like others have said, when the blur fires, the new element may not have received focus. The real trick though, is to know that document.activeElement holds the element that has focus. This answer will work even when focus changes for other reasons besides clicking
http://jsfiddle.net/mendesjuan/crenZ/
HTML
<input id="inp1" />
<input id="inp2" />
​
JS See Detect which form input has focus using JavaScript or jQuery
$('input').blur(function(){
// Need a setTimeout
// There is no guarantee of where the focus went, but after the
// current event is processed, it will be available
setTimeout(function(){
// The currently focused element
console.log(document.activeElement);
}, 0);
})​
Check this fiddle:
http://jsfiddle.net/pHQwH/
The solution sets the active element on document's mousedown which is triggered for all elements in the document and uses that to determine whether or not to executed the code in blur event.
CODE
var currElem = null;
$(document).mousedown(function(e) {
currElem = e.target;
});
$('#f1').blur(function() {
if(currElem != null && currElem.id != "f3") {
$(this).val('F1: clicked elem is not f3, blur event worked');
// do your blur stuff here
}
else {
// for demo only, comment this part out
$(this).val('F1: clicked elem is f3, no blur event');
}
});
Use event.target - The target event property yields the element that triggered the event.
<html>
<head>
<script type="text/javascript">
function getEventTrigger(event)
{
var x=event.target;
window.alert("The id of the triggered element: " + x.id);
}
</script>
</head>
<body >
<p id="p1" onmousedown="getEventTrigger(event)">
Click on this paragraph. An alert box will
show which element triggered the event.</p>
</body>
</html>
This is not possible with a blur event listener alone. The blur event – which it is triggered by – occurs when an element loses focus. The click event occurs after an element receives focus, after the focus event for the same element. As a result, there is a state in-between in which neither element has the focus:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>DOM Test Case: Event Order</title>
<script type="text/javascript">
function debugEvent (event)
{
/* or window.alert(…); */
console.log(event, "on", event.target || window.event.srcElement);
}
function body_load ()
{
var elements = document.forms[0].elements;
var foo = elements["foo"];
var bar = elements["bar"];
foo.onblur = bar.onfocus = bar.onclick = debugEvent;
}
</script>
</head>
<body onload="body_load()">
<h1>DOM Test Case: Event Order</h1>
<form action="">
<div>
<input name="foo">
<input name="bar">
</div>
</form>
</body>
</html>
See also: DOM Level 2 Events Specification: HTML Events
What you could do is to use a listener for an event that occurs before the blur event. The mousedown event suggested by #techfoobar appears to be such an event (in Chromium 18.0.1025.168 (Developer Build 134367 Linux)), but there is no standard, no draft specification even, to back that up¹. See also: What is the event precedence in JavaScript?
Anyhow, that solution is incomplete as both a blur event and a click event may be triggered also by pressing a key (combination), for example. Handling the keydown event should help then, but the solution would still be incomplete.
Therefore, it is likely that your approach is wrong.
¹ Of course, if you are limiting yourself to jQuery and similar libraries (which the $j() calls indicate), you could also satistfy yourself to testing in the subset of browsers that they claim to support. But you will have to re-test that with every new browser, and every new version of browser and library.

Checkbox inside an anchor click behavior

Consider following snippet:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
</head>
<body>
<form>
<a id="a" href="http://google.com">Goooooogle</a>
</form>
<script>
$(function() {
var checkbox = $('<input type="checkbox"></input>');
checkbox.prependTo($('#a'));
checkbox.click(function(e) {
e.stopPropagation();
// do something useful
});
});
</script>
</body>
</html>
I want to get a checkbox inside <a>, and get following on-click behavior:
Toggle check mark normally as usual
Do something useful like AJAX-request
Stay on this page, i.e. not be redirected to an a href
Also I want to not override default behavior if I click anywhere in a, but not on checkbox. I.e. I want to allow to execute all event handlers associated with a click itself.
I thought that should be pretty easy, but I can't get desired behavior. Either:
I get redirected to Google if I put a code provided.
I don't get check mark toggled if I use e.preventDefault() of return false;. Furthermore in that case checkbox ignores explicit checkbox.attr('checked', 'checked') and all other possible ways to set the check mark.
Where is the catch?
UPD: This works as expected in Chrome, e.g. I'm not redirected on click, but fails in Firefox. Is there cross-browser way?
Well, it looks like a known Firefox bug, which leads to following link on checkbox click regardless of handlers' code. As a bit dirty workaround one can use:
var checkbox = $('<input type="checkbox"></input>');
checkbox.prependTo($('#a'));
checkbox.click(function(e) {
setTimeout(function() { checkbox.prop('checked', !checkbox.prop('checked')); }, 10);
// do something useful on clicking checkbox and but not surrounding link
return false;
});
I know this is an old question but some may still be curious since it was never really fully answered without a messy hack or workaround. All you have to do is simply check where the event's target originated.
So using your example (jsfiddle):
// Don't change pages if the user is just changing the checkbox
$("#a").click(function(e) {
//e.preventDefault(); // Optional if you want to to keep the link from working normally
alert("Click came from: " + e.target.tagName);
if (e.target.tagName != "INPUT") {
// do link
alert("Doing link functionality");
} else {
// do something useful
alert("Doing checkbox functionality");
}
});
I Know this question is over 5 years old, but I had the same issue recently and the work-around I found was to add an onclick function to the checkbox and in that function call event.stopImmediatePropagation().
from w3schools: "The stopImmediatePropagation() method prevents other listeners of the same event from being called"
ie...the anchor.
function checkbox_onclick(event){
event.stopImmediatePropagation();
}
here's a modified script
var checkbox = $('<input type="checkbox"></input>');
var a = $('#a');
a.unbind("click").click(function(e) {
e.preventDefault();
checkbox.attr('checked', !checkbox.attr('checked'));
});
checkbox.prependTo(a);
checkbox.click(function(e) {
e.stopPropagation();
// do something useful
});
i unbind the click event on the <a> and rebind it with a event to check/uncheck the checkbox and also prevent the default.

Prevent text selection after double click

I'm handling the dblclick event on a span in my web app. A side effect of a double click is that it selects text on the page. How can I prevent this selection from happening?
function clearSelection() {
if(document.selection && document.selection.empty) {
document.selection.empty();
} else if(window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
}
}
You can also apply these styles to the span for all non-IE browsers and IE10:
span.no_selection {
user-select: none; /* standard syntax */
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
-moz-user-select: none; /* mozilla browsers */
-khtml-user-select: none; /* webkit (konqueror) browsers */
-ms-user-select: none; /* IE10+ */
}
To prevent text selection ONLY after a double click:
You could use MouseEvent#detail property.
For mousedown or mouseup events, it is 1 plus the current click count.
document.addEventListener('mousedown', function(event) {
if (event.detail > 1) {
event.preventDefault();
// of course, you still do not know what you prevent here...
// You could also check event.ctrlKey/event.shiftKey/event.altKey
// to not prevent something useful.
}
}, false);
Some dummy text
See https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
In plain javascript:
element.addEventListener('mousedown', function(e){ e.preventDefault(); }, false);
Or with jQuery:
jQuery(element).mousedown(function(e){ e.preventDefault(); });
FWIW, I set user-select: none to the parent element of those child elements that I don't want somehow selected when double clicking anywhere on the parent element. And it works! Cool thing is contenteditable="true", text selection and etc. still works on the child elements!
So like:
<div style="user-select: none">
<p>haha</p>
<p>haha</p>
<p>haha</p>
<p>haha</p>
</div>
A simple Javascript function that makes the content inside a page-element unselectable:
function makeUnselectable(elem) {
if (typeof(elem) == 'string')
elem = document.getElementById(elem);
if (elem) {
elem.onselectstart = function() { return false; };
elem.style.MozUserSelect = "none";
elem.style.KhtmlUserSelect = "none";
elem.unselectable = "on";
}
}
For those looking for a solution for Angular 2+.
You can use the mousedown output of the table cell.
<td *ngFor="..."
(mousedown)="onMouseDown($event)"
(dblclick) ="onDblClick($event)">
...
</td>
And prevent if the detail > 1.
public onMouseDown(mouseEvent: MouseEvent) {
// prevent text selection for dbl clicks.
if (mouseEvent.detail > 1) mouseEvent.preventDefault();
}
public onDblClick(mouseEvent: MouseEvent) {
// todo: do what you really want to do ...
}
The dblclick output continues to work as expected.
If you are trying to completely prevent selecting text by any method as well as on a double click only, you can use the user-select: none css attribute. I have tested in Chrome 68, but according to https://caniuse.com/#search=user-select it should work in the other current normal user browsers.
Behaviorally, in Chrome 68 it is inherited by child elements, and did not allow selecting an element's contained text even if when text surrounding and including the element was selected.
or, on mozilla:
document.body.onselectstart = function() { return false; } // Or any html object
On IE,
document.body.onmousedown = function() { return false; } // valid for any html object as well
If you are using Vue JS, just append #mousedown.prevent="" to your element and it is magically going to disappear !
Old thread, but I came up with a solution that I believe is cleaner since it does not disable every even bound to the object, and only prevent random and unwanted text selections on the page. It is straightforward, and works well for me.
Here is an example; I want to prevent text-selection when I click several time on the object with the class "arrow-right":
$(".arrow-right").hover(function(){$('body').css({userSelect: "none"});}, function(){$('body').css({userSelect: "auto"});});
HTH !
To prevent IE 8 CTRL and SHIFT click text selection on individual element
var obj = document.createElement("DIV");
obj.onselectstart = function(){
return false;
}
To prevent text selection on document
window.onload = function(){
document.onselectstart = function(){
return false;
}
}
I know this is an old question but it is still perfectly valid in 2021. However, what I'm missing in terms of answers is any mentioning of Event.stopPropagation().
The OP is asking for the dblclick event but from what I see the same problem occurs with the pointerdown event. In my code I register a listener as follows:
this.addEventListener("pointerdown", this._pointerDownHandler.bind(this));
The listener code looks as follows:
_pointerDownHandler(event) {
// Stuff that needs to be done whenever a click occurs on the element
}
Clicking fast multiple times on my element gets interpreted by the browser as double click. Depending on where your element is located on the page that double click will select text because that is the given behavior.
You could disable that default action by invoking Event.preventDefault() in the listener which does solve the problem, at least in a way.
However, if you register a listener on an element and write the corresponding "handling" code you might as well swallow that event which is what Event.stopPropagation() ensures. Therefore, the handler would look as follows:
_pointerDownHandler(event) {
event.stopPropagation();
// Stuff that needs to be done whenever a click occurs on the element
}
Because the event has been consumed by my element, elements further up the hierarchy are not aware of that event and won't execute their handling code.
If you let the event bubble up, elements higher in the hierarchy would all execute their handling code but are be told to not do so by Event.preventDefault() which makes less sense to me than preventing the event from bubbling up in the first place.
Tailwind CSS:
<div class="select-none ...">
This text is not selectable
</div>
I had the same problem. I solved it by switching to <a> and add onclick="return false;" (so that clicking on it won't add a new entry to browser history).

Categories