I am building a chat application and I am trying to make sure that any time a user presses a key, the key they press ends up getting entered into a specific element (an editable HTML document ui.rte1Content in an iframe ui.rteIFrame, to be exact). This should happen no matter which element on the page currently has focus. I only care about supporting Firefox and Chrome.
So far, I've registered a handler on the window.onkeydown event:
function captureKeyDown(e) {
console.log("Capturing: " + e.keyCode);
// We ignore certain keys such as page up, as well as keys pressed with
// alt or ctrl, except for a few select combos like ctrl+b
if(!ignoreKeys.contains(e.keyCode) && !e.altKey &&
(!e.ctrlKey || (e.ctrlKey && validCtrlKeys.contains(e.keyCode)))) {
ui.rte1Content.focus(); // Chrome prefers this.
if(!rteHasFocus) {
ui.rteIFrame.focus(); // Firefox prefers this
}
//alert("A commented out alert");
}
}
This works perfectly in Firefox: rteIFrame gets focus, the key that's been pressed shows up, and we carry on. However, in Chrome (23.0.1271.95), while rte1Content correctly gets focus in time for the NEXT letter to show up, the initial letter that first triggered the event disappears into the ether.
For what it's worth, if I uncomment out the alert statement, the letter shows up just fine in Chrome. I have no idea why this is.
Does anyone have any suggestions about how I can get this to work?
For the "alert() thing", it's simply because in Chrome the focus is lost when an alert() occurs. To test that, try to open the JavaScript console (CTRL+SHIFT+J in Chrome, CTRL+SHIFT+K in Firefox), select something or focus on something on any page then type in the console alert("test");, you gonna see that the focus is lost. Then try in Firefox, the focus is kept.
Also I feel like you are doing stuff the complicated way ahah! Why not just using a <textarea> tag to store keyboard input ? Also, if you plan on making a chat application by passing data trough an iframe with the COMET technique or maybe some long pooling, etc.. I would really suggest that you google WebSockets as you gonna be able to make a more modern and optimized chat with this. It would be perfect also in your case because you seams to focus only on Firefox and Chrome, two browsers that correctly support WebSockets. :)
Related
I have an event I want to execute on key down in an input field. It does as much in Firefox. In chrome, however, it executes the event (a redirect) when I give the page any input (click, key down, etc). I can't seem to figure out why. Any ideas?
Here's the javascript:
var yum = document.getElementById("username");
var form = document.querySelector("div.resp-wrapper form[name='register']");
form.setAttribute("autocomplete", "off");
yum.addEventListener("keydown", function handler() {
window.location.href = "https://giphy.com/gifs/troll-you-mad-face-eVy46EWyclTIA";
this.removeEventListener("keydown", handler);
});
This is the page I'm working on [Link Deleted]; you can see the problem there while it's live. I'll be removing this link eventually.
Oh I guess I should probably mention that this is an invisible form field (it's a honeypot). It's between the captcha and the last visible form field. You can run a test by clicking where the field would be and pressing any key.
UPDATE: I am able to reproduce on my Windows machine; chrome version 74.0.3729.131 (Official Build) (64-bit). On my android, the behavior is the same as well (touching anywhere on the page redirects me) - version 74.0.3729.136. But was not able to reproduce on my Mac chrome version 71.0.3578.98.
Figured it out; and, of course, it was something stupid. I removed the CSS from the form field and realized that, even though I had cleared my cache and browser history, several times, that didn't prevent Chrome's autofill feature from populating that field EVERY time.
When I removed the CSS I could see the field was always populated whenever I visited the page. Chrome had been filling in my email address (oddly, considering it's not an email field). I cleared my Chrome autofill settings and now the code works as expected. It's unfortunate that the autocomplete="off" attribute doesn't prevent this. I've read that usually this attribute is moot because the browser will override it anyway.
Background:
I have a textarea. I capture the Tab key event when the user is typing, and I insert a Tab character (\t) and prevent the browser from focusing on the next input.
This works without issue on Mac and PC, on all browsers.
Problem:
When using a Bluetooth keyboard attached to an iPad, this doesn't work. The document registers the tab key event, but as soon as I focus on the textarea, all tab key events are ignored and not sent to the browser. I have tested with text inputs as well, and see the same result.
Example: https://plnkr.co/edit/NQvxijj3ISZ0B48fSHvi?p=preview
Simple listener:
$(function(){
$("body").bind("keydown",function(e){
$("#bodyLog").append($("<div/>").html(e.keyCode));
return e.preventDefault();
});
});
When you have the body selected (NOT THE TEXTAREA), the tab key event is registered and the number 9 appears. Any other key event appears as well.
When you have the textarea selected, all keydown events are registered on both the body listener and the textarea listener... EXCEPT the tab key.
If anyone has a solution, I would be eternally grateful.
EDIT
I have "fixed" the issue by watching for 5 spaces, then converting that to a tab character.
I have researched this and can only figure that iOS does not want to release control of the TAB key when focused on inputs/textareas. I have tried visiting sites like Google Docs to see if they have gotten around it, but they force you to download the App rather than allowing you to edit files inside of Safari on iOS. I am guessing it is because iOS wants to control the tab key entirely. I have tried Chrome on iOS, but it functions the same, so I would say this is not a Safari issue, but an iOS issue.
A possible, but untested, workaround is to code an entire <div> to act like a textarea, and then replace the textarea with the div. Since the tab key works on all other elements, it should in theory work, but it would require quite a bit of Javascript and CSS to make an element act like another.
EDIT 2
I have discovered that using Option+Tab allows the tab key to be captured in the textarea. I don't feel that is satisfactory though. When I am typing a paragraph on a normal keyboard, I don't type Option+Tab, I just type Tab. As far as I can tell there is no way to capture the Tab key alone inside a textarea.
You can try using this library in order to have these events:
previousbuttonclick
nextbuttonclick
Then when you detect the element next to textarea is focused you come back to your textarea and insert whatever you want.
I believe this is known problem with tabs in iOS. I found similar question on stackoverflow. Just add this hack before your code:
var oldAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(eventName, eventHandler){
oldAddEventListener.call(this, eventName, function(e) {
if(e.target.id === "textarea" && e.keyCode===9){
e.preventDefault();
}
eventHandler(e);
});
};
Please check, it should work. Example
I have a very, very weird issue that only seems to be an issue in Chrome.
When a user comes on the website, the user cannot focus any element (via mouse click, if they focus it via tabbing, the elements don't get the 'focused' state either) and that's only an issue in Chrome. That is, until the user resizes the window, minimizes the window, opens a new tab, opens developer tools, etc. Reloading the page does nothing. However, as soon as focus is "enabled", the user can navigate/refresh with purging cache, etc., close the browser and open it again, and everything works normally - the elements get the 'focused' state normally.
This behaviour can only be reproduced in Chrome and not on localhost.
The difference between localhost and beta environment is:
beta env requires authentication (basic http auth)
files in development env are concated in a single JS and single CSS file and both are minimized
beta env includes hotjar, while there's no hotjar on localhost
There are no custom event listeners that would listen for the 'resize' event. There are no errors in console and all javascript that doesn't depend on focused element state gets executed correctly. Hover events and all CSS styling that depends on hovered state all work correctly.
The main issue is, that a form which has to be filled out and includes a datepicker, cannot be filled out and thus the users can't really interact with the page. Datepicker doesn't open and, as the input elements don't get the focused state, they don't visually change (CSS :focused selector isn't working either) and thus give the impression to the user that they cannot type in the normal text inputs (which works, after clicking on the input, it is possible to type in the input).
I have tried removing hotjar and the problem persisted. The only thing that made the problem go away was removing the basic auth, however, that is not an option in this stage (it's a closed beta test, so we need to limit the access only to the users with password).
I also find it extremely odd that basic auth would interfere with the focused state of elements, especially as the error persists after you refresh and only goes away as soon as you interact with browser itself (minimize, open new tab, do anything that resizes your browser window or document), after that it works correctly and there are no errors whatsoever.
The problem only started to appear recently, but I do not believe it's an issue with the app itself, as I tried rolling back to a couple months old build and the problem persists. All of that makes me believe it's a bug in Chrome, but what can be done to fix it?
EDIT: I also tried to add autofocus property to an input element and, in beta environment, it doesn't get focused.
So it seems it indeed is a Chrome bug that's present both on mobile (Android and iOS) Chrome browsers, as well as desktop Chrome browser (tested both on a Windows and a Mac). I submitted an official bug report. In the bug report, a fellow user made a website that's accessible only through basic auth and only has 2 basic inputs, the input should get a red border on focus. As expected, after opening the webpage in Chrome (for ease of use - incognito mode), the input doesn't get focus and the border doesn't change.
For those who are also affected by this bug in Chrome, you can track the bug progress here: https://bugs.chromium.org/p/chromium/issues/detail?id=740652
Meanwhile, here's a hacky solution for those interested:
$(document).on("ready", function() {
var $inputs = $("input");
$inputs.off("click.trick");
if (!sessionStorage.fixedChromeFocus) {
sessionStorage.fixedChromeFocus = "true";
$inputs.on("click.trick", function() {
var win = window.open("/", "_blank");
setTimeout(function() {win.close()}, 1);
$inputs.off("click.trick");
});
}
});
The goal is to, somehow, interact with the browser outside of the current page, to make it somehow lose focus. You cannot use JS to minimize browser, cannot resize it, cannot open dev tools. What you can do, though, is open a new window. Of course, if you open a new window immediately, a pop-up blocker (as most people have it) will block it and the window itself (or rather your current tab) won't lose focus. Opening a new window can only be done as a reaction to a user event (without triggering potential pop-up blocker).
I also use some browser detection so the code will only be executed for Chrome and, using server-side conditioning, only for builds that include basic auth.
What the code does, quite self evidently, is that as soon as a user clicks on an input, it opens a new tab and quickly closes it, 1ms later. To prevent this from happening all the time, on every page load, sessionStorage, which gets cleared automatically after tabs from that domain are closed, is used (and we've already established that once focus starts working correctly, it will work as long as you keep your browser open).
The effect of this code is that the user will see a quick white flash the first time he clicks on the input, but everything will work correctly
I'm trying to debug a JavaScript onFocus event attached to a bunch of text boxes on a page. The bug occurs when selecting a text box and then tabbing to the next text box. I'm trying to debug this by placing a break point in the onFocus event using the Chrome Developer Tools. The problem I'm facing is that when I select a text box and the break point is caught, Chrome Developer Tools steals focus and does not return it, so I can't tab to the next text box. Anyone have an idea for a work around? I guess I can resort to alert statements to print all of the information I need without using Chrome Developer Tools......
Chrome Dev Tools includes a Play/Pause button both in the Inspector and as an overlay to the webpage. Using the overlay prevents focus from landing on the Inspector.
Also, I've found the following type of logging solution to be easier to track than the interval method (thanks to less redundancy and the ability to pick up on changes that occur more rapidly than the interval):
$('*').on('focus blur', function(event) {console.log(event.type + " to:"); console.log(document.activeElement);});
One option for debugging tricky cases is to set an interval to poll the focus in the console.
setInterval(function() {console.log($(':focus')); }, 1000);
Type this in the console (update it to include whatever details you are interested in), hit enter, and then keep the console where you can see it while you do stuff in your UI.
*MDN docs for setInerval()
You are right, Chrome DevTools receive focus and do not restore it when you switch back to the debugged page. Feel free to file a bug at http://new.crbug.com (make sure you start the summary with "DevTools: " so that the bug can be assigned to the appropriate team as quickly as possible.)
On a side note, console.log() is a slightly better alternative to alert() as it allows formatted output.
There's a checkbox in the Rendering tool of Chrome DevTools labelled "Emulate a focused page". This prevents the webpage from getting blur events when you click on DevTools or other windows.
I have been looking into how you could use Javascript to direct focus to a Flash movie. I've seen it discussed on Stack Overflow and other sites and it seems you cannot do this reliably except in Internet Explorer. I am just calling the .focus() method on a Flash object via Javascript.
It does in fact work in Internet Explorer, but I don't like its behavior on Firefox or other browsers. Basically, I have a username/password login field INSIDE my Flash movie, and I want to give it focus when the Flash movie loads, so you can start typing your username immediately, without having to first click the field.
The problem with Firefox is that not only does it not set the focus, you can SEE a blinking cursor inside the field in Flash, which really indicates that the field has focus. However, you still have to click.
This is counterproductive on Firefox. I would rather not even attempt to set the focus if this is the behavior. I could of course check what browser is in use and determine whether to even call .focus(), but this functionality may change in later versions of Firefox. I'd love to have a better solution, that would:
Remember the current focus before the Flash movie is dynamically added to the page (this is how I do it, I cannot display the movie as part of the initial page load).
Attempt to set focus to the Flash movie.
Check if the focus WAS properly set, so I can expect that the Flash movie is actually receiving keystrokes without an additional click.
If focus was not set, revert to whatever was focused before the Flash movie was loaded.
I am not sure how (or if) this can be done but I'd love to find out. I think document.activeElement may be useful, but I was not able to get very far with that. Thanks for any help!
This may help. It's a kind of workaround using javascript to avoid having to focus on the actual Flash object at all...
https://github.com/englandrp/Cross-browser-Flash-tabbing-and-focus-solution
Try something like this:
private function setInitialFocus():void {
myInput.setFocus();
ExternalInterface.call("function() { var app = document.getElementById('myApp'); app.tabIndex = 0; app.focus(); }");
}
You will also want to set the tabIndex to 0 on your input control.
http://kb2.adobe.com/cps/155/tn_15586.html
Firefox Focus and Actual Links
and this one too