Prevent loss of element focus (Need cross-browser solution) - javascript

I'm using the following solution to prevent loss of focus of the #content textarea when the user has clicked on a .box element:
// Detect latest element clicked
$(document).mousedown(function(e) {
lastElClicked = $(e.target);
});
// Prevent loss of focus for textarea when clicking on tools
$("#content").on("blur", function(event) {
if (lastElClicked.attr('class') == 'box'){
event.preventDefault();
this.focus();
return false;
}
});
In a few words, on mouse down save the target element that has been clicked. On the blur of the #content textarea check if that last element clicked was a .box. If it was then prevent default, refocus the #content textarea and return false.
My solution works perfect under Chrome but I still loose focus under Safari and Firefox. How can I make this work cross browser?
EDIT:
The problem with the solutions offered is that the element actually looses focus and is refocused after. In Chrome with the code above I never actually loose fucus, which means selected text stays selected.

EDITED:
try this:
// Detect latest element clicked
$(document).mousedown(function(e) {
window.lastElClicked = $(e.target);
});
// Prevent loss of focus for textarea when clicking on tools
$("#content").on("blur", function(event) {
if (window.lastElClicked.attr('class') == 'box'){
event.preventDefault();
var that=this;
setTimeout(function(){
$(that).trigger('focus');
},200);
window.lastElClicked="";
return false;
}
});
Also this is a nice article on this bug which appears to be on Safari's part: http://bugs.jquery.com/ticket/7768
Alternatively you could try this one:
$('.box').click(function(event){
event.preventDefault();
$('input').each(function(){
$(this).trigger('blur');
});
setTimeout(function(){
$('#content').trigger('focus');
},200);
});
finally I have to mention that it still loses the focus on the highlighted text which seems to me as an impossible task to achieve in this case!

Related

Open bootstrap dropdown on input focus

I have an input that when clicked shows a bootstrap 4 dropdown BUT I need it to open when a user tabs to it as well for ADA accessibility.
If I use a focus event that uses $('#input-name).dropdown('toggle') it works fine, but when the input is clicked focus fires first which opens the dropdown and then the click event closes it.
I have tried e.preventDefault(); e.stopPropagation(); but neither help solve this issue.
events: {
focus #healthPlanMenu": "openDropDown"
}
openDropDown: function (e) {
if ($('#healthPlanMenu').find('.dropdown-menu:no(.show)')){
$("#healthPlanMenu.dropdown-toggle").dropdown('toggle');
}//fails
$("#healthPlanMenu.dropdown-toggle").dropdown('toggle');//fails
$( "#healthPlanMenu" ).click();//fails
}
So ideally you'd probably solve this by having the focus event set the dropdown's state to open, that way if it gets "reopened" by the click event, no problem. However, as far as I can tell there is only a toggle option with the jQuery API; seems unnecessarily limiting...
Given that, we can know if a click is coming after our focus event by using mousedown. So a somewhat hacky way to solve this problem is to disable our focus event if we know a click is coming.
(function() {
var disable = false;
$('#healthPlanMenu.dropdown-toggle')
.on('mousedown touchstart', function() {
disable = true;
})
.on('focus', function() {
if (!disable) {
$(this).dropdown('toggle');
}
})
.on('mouseup touchend',function() {
disable = false;
})
})()
I don't know if the touchstart and touchend are necessary as most browsers probably fire mouse events on touch as well. But better safe than sorry.

Fire event with right mouse click and Paste

I want to fire an event in a textarea immediately after paste some text inside the textarea. I can do that when Shift+Ins is used; however, I cannot do it when right mouse button and then paste (from the drop down menu) is chosen. Keyup fires after Shift+Ins. None of the rest fires when Paste is chosen after right mouse button clicking... What do I have to do?
<textarea name="message" id="message"></textarea>
$("#message").on('keyup contextmenu', function(event) {
alert("ok");
});
http://jsfiddle.net/f29vuwoL/7/
Thank you
Most browsers support the input event, which is fired when something is pasted or otherwise added, regardless of how:
$("#message").on('keyup contextmenu input', function(event) {
alert("ok");
});
Updated Fiddle
Note that using input is the most general method, firing when the control gets input regardless of how, and so if you hook multiple events (as above), you'll get multiple calls for the same input. For instance, if you hook both keyup and input, on browsers that support input, you'll get two calls. Similarly for paste and input when the user pastes, on browsers that support both.
If you need to support browsers that don't have either input or paste, I'm afraid the unfortunate answer is that you need to poll. Still, polling every (say) 250ms isn't asking the browser to do that much work, and you can feature-detect whether it's necessary:
var message = $("#message");
var events = null;
var previous;
if ('oninput' in message[0]) {
// Browser supports input event
events = "input";
} else if ('onpaste' in message[0]) {
// Browser supports paste event
events = "paste keyup contextmenu";
}
if (!events) {
// Ugh, poll and fire our own
events = "pseudoinput";
previous = message.val();
setInterval(function() {
var current = message.val();
if (current != previous) {
previous = current;
message.trigger(events);
}
}, 250);
}
console.log("Using: " + events);
message.on(events, function(e) {
console.log("Got event: " + e.type);
});
Updated Fiddle
You should use input event callback. See the demo here
You can use the dedicated paste event:
$("#message").on('paste', function(event) {
alert("ok");
});
Updated jsFiddle
However you might want to check browser support - I don't think jQuery normalizes this event.
If you need IE support, it might be a little more difficult, but it depends on your requirements - does it absolutely need to be a paste action? If not, TJ Crowder's answer is the way to go.
The on input is useful if you want to detect when the contents of a textarea, input:text, input:password or input:search element have changed, because the onchange event on these elements fires when the element loses focus, not immediately after the modification.The oninput event is supported in Internet Explorer from version 9.
$("#message").on('input propertychange', function() {
console.log($(this).val());
});
Fiddle

focusout focusin browser tab switch

Is there elegant way to determine if focusout focus is suppose to end up in element that is part of current window? Well I guess it would be enough to know id of element that was focused in, that caused focus out.
$('body').on("focusout", ".control-container > input", function () {
var escapeContext = ???
if (escapeContext within currentWindow)
{
DoSomething();
}
else
{
DoNothingAndStayInFocus();
}
});
My goal is to make DOM non-reactive if user changes browser tab, just as if you switched to another window.

jquery - field selects all text then unselects it on focus

trying to figure out why this is happening - I have an input text field and I want all the text to be highlighted when the field receives focus. This happens, very quickly, and then all of the text is unselected. Any idea why this would occur? Here's the code I'm using:
$("#permalink").focus(function(){
this.select();
});
You need to override the mouseup event on the input element (as mentioned in this post - thanks MrSlayer!)
See here for example: http://jsfiddle.net/f8TdX/
This is an issue in WebKit. The best option is to use a combination of the focus and mouseup events. The following comes from another answer to a similar question.
$("#permalink").focus(function() {
var $this = $(this);
$this.select();
window.setTimeout(function() {
$this.select();
}, 1);
// Work around WebKit's little problem
$this.mouseup(function() {
// Prevent further mouseup intervention
$this.unbind("mouseup");
return false;
});
});
Give this a shot
$(document).ready(function() {
$("input:text").focus(function() { $(this).select(); } );
});
Select all contents of textbox when it receives focus (JavaScript or jQuery)

Action on blur except when specific element clicked with jQuery

There are two elements in play:
$('#myInput') // an input field for search
$('#myList') // a list to display search results
I want to hide the list when the input no longer has focus, like so:
$('#myInput').blur(function() {
$('#myList').hide();
});
This works great, except when a list item is clicked, because the blur event fires and hides the list before the click is registered. The goal is for the list to stay visible when any part of the list is clicked, even though this will cause the input to blur.
How can I do this? Thanks!
You can accomplish this by keeping a global variable, and setTimouts, to wait a delay of 200ms and then check if one of the 2 elements have focus.
var keepFocus = false;
function hideList(){
if(!keepFocus){
$('#myList').hide();
}
}
$('#myInput').blur(function() {
keepFocus = false;
window.setTimeout(hideList, 200);
}).focus(function(){
keepFocus = true;
});
$('#myList').blur(function() {
keepFocus = false;
window.setTimeout(hideList, 200);
}).focus(function(){
keepFocus = true;
});
I've faced with the exact same problem, so this is how I solved it.
I came up with the fact that blur() fires earlier than click().
So I've tried to change click() to mousedown() and found out that mousedown() fires before blur().
And to imitate click() you'll have to fire mousedown() and then mouseup()
So in your case I would do something like this:
var click_in_process = false; // global
$('#myList').mousedown(function() {
click_in_process = true;
});
$('#myList').mouseup(function() {
click_in_process = false;
$('#myInput').focus();
// a code of $('#myList') clicking event
});
$('#myInput').blur(function() {
if(!click_in_process) {
$('#myList').hide();
// a code of what you want to happen after you really left $('#myInput')
}
});
Demo / example: http://jsfiddle.net/bbrh4/
Hope it helps!
You need to be able to say "do this blur() unless the list gains focus at the same time".
This question says how to detect if an element has focus: Using jQuery to test if an input has focus
Then all you need to do is:
$("#myInput").blur(function () {
if (!$("#myList").is(":focus")) {
$("#myList").hide();
}
});
Pigalev Pavel's answer above works great.
However, If you want an even simplier solution, you can just "prevent default" in the "mousedown" of an element to prevent the blur event from taking place. (since preventing default actually means that in the end, the input never looses focus in the first place!)
Of course, this is only if you're alright with preventing default in the div. It does have some side-effects, like the text is no longer selectable. As long as that's not an issue, this will work.
I suppose if you hold the mouse down over the div, move the mouse outside of the div, and then release the mouse, it also doesn't fire the "blur" event. But in my case, I wasn't too worried about that either, since the click started in the target div.
$("input").focus(function(){
$(this).val("");
});
$("input").blur(function(){
$(this).val("blur event fired!");
});
$("div").mousedown(function(e){
e.preventDefault();
})
div{
height: 200px;
width: 200px;
background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input>
<div>
Click here to prevent blur event!
</div>
The best way to do this is to attach an event handler to the body element, then another handler to the list that stops event propagation:
$(body).click(function () {
$("#myList").hide();
});
$("#myList").click(function (e) {
e.stopImmediatePropagation();
});
This listens for a click outside of #myInput and hides #myList. At the same time, the second function listens for a click on #myList and if it occurs, it prevents the hide() from firing.

Categories

Resources