Handling keys happens even when textarea is focused - javascript

I have a canvas app where I handle window's keyup and other events. This works fine. However, now I've created a popup div with a textarea in it, and I don't want my keyup handling to be active when the textarea is focused (or when the popup is visible).
I could set a bool isPopupVisible and check for that in my keyup handling, but it strikes me that much more elegant would be to just use the standard focus management of HTML. So I tried handling the canvas's keyup event rather than the window's, but now the problem is that the canvas never receives focus (not even if I click on it) so it doesn't receive any key events. Apparently most HTML elements can't receive focus.
What would be a good way to resolve this?
Edit: It now occurs to me that what I want is in effect a modal dialog box, which HTML doesn't natively support. To support this modality, it's normal to implement it manually with a bool as I initially planned. Standard HTML focus doesn't provide for that, even if I could get the canvas to receive focus. Because the user can switch focus back to the canvas by clicking on it even when the popup is still visible (undesirable).
So I guess I withdraw my question.

Related

Is it possible to distinguish focus events due to clicks vs. events due to tabbing?

In Chrome (85) and FF (80), clicking on a tabbable element gives it focus. Of course, one can focus by tabbing to the element too, and the focus events that come from either seem to be identical (view dump in browser console: the focus event is quite big):
document.getElementById('main').addEventListener('focus', console.log)
focus here
This becomes problematic for the following: I'm implementing a double-click behavior, where one must select an item with one click, then click again to follow it. I'd also like users to be able to use tab + enter or tab + single-click to follow through.
While I'd strongly prefer to use the default browser behavior to do most of the work, given all I'm adding is one extra click, this seems to be impossible to do without listening for keystrokes. This is because if indeed the two above events are indistinguishable, then one can't tell the difference between:
a tab followed immediately by click, and
a single click that generates both a focus and click event.
Event order can't be trusted, and unfortunately FF has focus first before click anyways.
Is there something in the focus or click events that I'm overlooking that I could use to check where that event is coming from?

jQuery Validate: Detecting underlying click instead of blur

I have a form that I create within a Bootbox (itself a layer on top of Bootstrap's modal). Once it is created, I call
$('#myForm').validate()
on it.
The desirable part of the behaviour is that now as the user tabs through the forms, they can see immediate feedback that they've messed up one of the fields. Entered a non-email address before hitting "tab" or clicking elsewhere? Warning and error message. Great!
But the undesirable thing is that the blur eats other events. So, if a user instead chooses to hit "cancel" (knowing full well that the form is invalid), the click on the cancel is not heard and its handler will not fire. A second click (now that the focus is off the form altogether) and cancel fires as expected. I don't want the users to have to click twice.
I saw a technique for disabling the blur altogether, but then the desirable behaviour described above is then lost, which I do not want either. Ideally, a "well, I blurred, but I also know what the user was clicking" is what I'm after.
[EDIT TO ADD:]
It has come to my attention that this is confusing, so let me try a different approach to the question: is it possible to be working on a form (that has had .validate() called on it), then click on any other clickable item on the whole page and have its click handler successfully fire?
[EDIT AGAIN:]
Based on Sparky's demo, I wired up a warning to show below the inputs on blur. So, to see the problem in action, fire up this fiddle: https://jsfiddle.net/bd1fhpu3/
Then click into one of the input fields BEFORE clicking "just a button". Click in an upper sliver of "just a button" to make sure that the warning labels have pushed it out of the cursor's hotspot on release of the mouse button.
Anyhow, this just explains what the problem is. Solving it is probably not within the scope of the question anymore, but it seemed worth sharing in case anybody else comes across this. To solve, I will either need to override Bootbox's click event to be a mousedown event instead of a click (then you don't need to press and release), or I can "Band-Aid"(tm) the solution by avoiding relocating the button. Maybe a static-height dialog that's tall enough to accomodate the form and any possible warnings. Definitely somewhat of a "hack" like this because you just never know if you're going to do other things later that make the problem appear again. But it'd be a quick and easy temp fix.
You cannot use the built in onfocuout function since the JavaScript cannot possibly know the different between focusing out to another field and focusing out to the cancel button.
You'll have to completely disable onfocusout and write some custom event handlers.
Your code is sparse, so my answer will be very generic.
$('#myForm').validate({
// other options here
onfocusout: false; // disable default blur event
});
Then write an event handler that programmatically triggers validation on the form when they focus to an input, and will do nothing when they focus over to anything, like a cancel button.
$('#myForm input').on('focus', function() {
$('#myForm').valid(); // trigger validation on the form
});
However, this will trigger validation on the entire form. If you only want to trigger validation on the one field losing focus, then you're back to square one, because the event only knows focus was lost, not where it's going.
Just for posterity, here's an "answer" such as it is. Maybe it will help somebody SOME day; you just never know.
There is no code that is operating "incorrectly" and therefore there is not really a fix nor code sample to provide. Here's what was happening:
User is in focus in field
User presses mouse button down (but the release action hasn't happened yet)
Blur event fires, which causes form error warnings to appear below the fields. This also had the net effect of pushing the "cancel" button down the Y axis of the screen
User releases the mouse button, which would normally complete the "click" handler.
HOWEVER, in #4, since the "cancel" button is no longer under the cursor, the click event listener bound to the button does not fire.
The demo, for as long as it lives on the internet, will be in a comment below. However, providing a code sample to go with it is pointless. When the demo dies, I will remove the comment.
Possible Steps (workarounds/hacks) that I elected NOT to pursue thus far:
Modify the dialog such that the button does not move when mousedown event fires, meaning the "click" event is completed successfully
Provide custom code that substitutes the mousedown event for the click event on the button. However, this causes a loss of fairly common UI convention
Force user to press ESC to cancel, rather than clicking a button
[credit to Tieson T. via comment] One possible option, if you can use some custom styles on the error messages, is to hide them with visibility: none rather than display: none. The former would hide the text but still reserve the vertical space of the text, which the latter doesn't (hence why your modal is expanding). This would keep the button from possibly shifting during the focusout event. You would wind up with extra whitespace, but you could knock some of that off by removing the bottom margin on the form-group (assuming you're using it)
I'm sure there are other workarounds, but that's a starting point.

Trigger a spellcheck in a contenteditable div

I am making an editor without relying on contenteditable, in order to get a clean, controlled output. So I'm catching all keyboard and mouse events, building a model and creating a DOM view from that model.
Since I need spellcheck, I activated contenteditable in divs in my view. The user doesn't interact with it, because I'm catching all events.
The problem I have is that spellchecking only seems to be activated on user input on the contenteditable div, which in my case happens only when I right-click somewhere on the text (because I'm not catching that). I've found a question that just says we shouldn't expect spellchecking to be active at the beginning - but in my case even when the user types, spellchecking doesn't happens (because he doesn't type in the contenteditable, I'm building it).
HTML spellcheck in contenteditable div not working after span
So is there a way I can trigger an event that would make the browser think the user is interacting with the contenteditable?
Update: that's only for Chrome, in Firefox the spellchecker works even without events directly caused by the user.

Catching all changes to the contents of an input box using JavaScript/jQuery

I have a page with an input box, and a function that processes the value of this input box and produces piece of text. I want this text to always be up to date in relation to the contents of the input box, so I've attached a couple of event handlers to it with jQuery to catch any changes:
$('#input').bind('keyup cut paste', function(){...});
This works well in most cases. Whenever the user modifies the contents using the keyboard in any way, or right-clicks to use the cut or paste functions, the text is updated immediately. However, there are two events I still haven't figured out how catch, if it's even possible to do so:
When the user selects a of text and drags it do a different position in the input box
When the user uses the Delete action in the right-click context menu
Both of these can of course be detected by binding the change event, but the problem with that approach is that it doesn't fire until the input box loses focus. The whole point of these bindings is to have the text update in real-time as the value of the input box changes, so change is no good.
English is my second language so I could simply be bad at wording my Google searches, but so far they've turned up nothing. I haven't found any solutions to this after digging through a couple of related Stack Overflow pages either, so I'm asking here. Is there an event binding for this that I don't know of? If not, is there a different approach I could take? Or is this simply not possible with plain JavaScript?
In non-IE browsers, you can handle the input event.
In IE, you can handle the propertychange event.
Demo (works in all browsers)
It's possible this SO question (and related jsfiddle) might answer your question.
(On the linked jsfiddle, put text in the top box to test)
In other words, bind to mouseup and mousedown, etc.
If you can't find a combination of events that cover all cases, you may want to use setInterval(function() {... }, period). You could play around with the period to see how well this works.

IE, textarea value is not changed when pressing buttons

I have a really nasty problem with focus in Internet Explorer.
I have a textarea for inputting text. This textarea is not visible for the user and is only used to provide robust text input for a more advanced view.
As the textarea isn't visible and shouldn't be I use textarea.focus() in the JavaScript to activate text-input. This has worked fine until now where I get really weird results.
For the textinput I basically use this event plus an exact copy for onkeypress.
textarea.onkeyup = function (e) {
//textarea.value contains the full text
//Update the view with this value
};
The problem is that sometimes textarea.value is not updated. I can even see the button in e.keyCode on the keyup event above but the value isn't changed.
This seems to happen after I have clicked somewhere on the page, but this does not trigger a blur-event. I'm logging the onfocus- and onblur-events so I can see when the textarea loses focus but it doesn't. And i still receive the keyup/press/down events.
If I try to refocus the textarea with textarea.focus() the problem remains. A workaround I found though is to focus the window with window.focus() and right after call textarea.focus().
The problem with this is that focus is a really expensive operation in IE (no kidding) and since I cannot detect when this problem will happen I have to keep doing it with certain interval which seriously affects the performance of my application (involves animation etc).
I use the exact same code for other browsers and do not have this problem there.
Change the identifier to something less generic like "textAreaAdv", IE sometimes get confused with this word.

Categories

Resources