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
Related
I've come across some strange functionality on chrome, mobile.
When I try to focus on an element on chrome, it doesn't work when you try to just load the input, getItById and do .focus(). However, if you wrap it in an event listener attached to a button, and click the button with your mouse, it works fine.
So, I tried to trick it by seeing if you could call btn.click(), but that doesn't activate the .focus()
Have a go below: On mobile, chrome (at least for iOS), load the page. You should get an alert 'Clicked', but it won't focus on the input. Then, try clicking on the button. You will get both the alert AND the focus works.
I found this interesting and wanted to see if people knew of a workaround.
Link here - jsfiddle
const btn = document.getElementById('button')
btn.addEventListener('click', () => {
alert('clicked')
const input = document.getElementById('input')
input.focus()
})
btn.click()
<input id="input" type="text">
<button id="button">Button</button>
Edit
Another thing I've noticed, is that if you put your phone go to sleep, and open it again, the focus() works without the click.
Edit 2 - added link for mobile
Why does this happen?
Because mobile devices usually need to change the screen dimensions when a keyboard is shown, they come with some restrictions on when a focus event can be triggered. This is intentionally limited browser behavior on touch devices to guarantee a good UX and avoid performance issues of resizing the browser window ( = potentially very expensive style recalculation).
There's some cross browser differences in how far these restrictions go, and some browsers have bugs on top of that.
But in general they all require an actual user interaction to have happened not too long before the focus is programmatically triggered. Using btn.click() is not the same as an actual touch event, and so the browser will ignore it seeing there was no recent touch event.
On a tracking issue on this behavior for Webkit, Apple provides a motivation:
We (Apple) like the current behavior and do not want programmatic focus to bring up the keyboard when you do not have a hardware keyboard attached and the programmatic focus was not invoked in response to a user gesture. Why you may ask...because auto bringing up the software keyboard can be seen as annoying and a distraction to a user (not for your customers, but for everyone not using your app) given that:
We bring up the keyboard, which takes up valuable real estate on screen.
When we intent to bring up the software keyboard we zoom and scroll the page to give a pleasing input experience (or at least we hope it is pleasing; file bugs if not).
This similar issue with the autoplay attribute, which also requires a gesture (or page load) to have happened recently enough, could be helpful in understanding the kind of problem.
How to work around these limitations?
Most of the time
Likely you don't need to, as most code that would trigger focus is running as a response to a user action and will be allowed to trigger focus. I didn't find data yet on how big the window of time is, but I guess it's big enough that in regular cases it's not a problem (unless you set timeouts of course).
A possible problem for those cases is the script would run so long that the event is already considered too long ago. In fact that's what happened in the related autoplay issue, where the code would request some network resource, and only after the response would trigger the video to play. Depending on the speed of the network/device the video would sometimes auto play, and sometimes not.
Technically the same could happen with an input that is only focused after a network delay making it not show the keyboard. As long as your code doesn't do any network requests you won't have this kind of problem.
On page load
This is definitely not a "fix" for the problem, but you can do a best effort to manage focus on page load by using the attribute specifically made for it. This still won't make a keyboard appear when it otherwise wouldn't.
The autofocus attribute is at least partially supported on all browsers.
Perhaps just calling focus() directly in a script on page load works, but again there's a chance that this code runs too long after the page started being displayed, especially on slower devices. This probably also happens when adding HTML with the autofocus attribute programmatically (e.g. React). If the initial HTML contains the autofocus attribute on the right element that shouldn't occur.
There is deinfitely something weird happening here.
It seems "part" of the DOM thinks that the input element is in focus initially, but chrome does not complete the focusing. For exmaple, if the background is set with:
document.activeElement.style.backgroundColor = "pink";
Then the input element's background is pink. So, some part of chrome's DOM thinks the input element is in focus.
Initially, in my case, the input element is rendered by chrome in its default non-focus styling.
The alert() seems to be interfering with the process. In my case, taking the alert out had the effect of changing the styling of the input element from non-focus styling to in-focus styling, but the cursor did not appear in the input element, nor did the pop up keyboard appear.
By:
removing the alert
wrapping the click inside a function
calling that function on load
fixed the problem in my case. Initially now the element is in-focus styled, the cursor appears in the element's box, and the keyboard pops up.
The solution to the posting by #HJo, January 2019, is to replace:
btn.click();
with:
function load() { btn.click(); }
remove the alert(),
and make the body tag as:
<body onload="load()">
#Peter. If this does not fix your problem too, can you please provide minimal code for your context.
const event = new Event('tap');
const btn = document.getElementById('button')
const input = document.getElementById('input')
btn.addEventListener('click', () => {
prompt('clicked')
input.focus();
})
window.onload = function(){
btn.dispatchEvent(event);
}
}
The code above works when the website tab is just opened, but not on reload for some reason. I tested it on an Ipad and Iphone so hopefully it works well on your end too.
Here's a link to a repl:
https://r.hackinggo306.repl.co
Edit: This seems to be the closest I can get, but also acknowledge the fact that mobile devices might be deliberately preventing this. (It would be annoying if a website looped this.)
On the mobile, you will need to use touchstart event instead of click event.
You can find it here. Hope this helps.
I think, this problem can occur, because of the your JavaScript script is executed before the DOM is Mounted.
so you can do different things,
One Thing
add defer keyword to script tag. Basically it does is, that script is only run after the DOM is mounted. See
Second Thing
Wrap window.onload event with your input focus functionality.
<script type="text/javascript">
window.onload = function () {
const btn = document.getElementById('button');
const input = document.getElementById('input')
input.focus()
}
</script>
window.onload event is only fired when the DOM is finishing mounting.so that may be your JavaScript script run before the input element is mounting.so add onload event to your code.see this
I want to have virtual keyboard for jquery terminal, here is my test code: http://terminal.jcubic.pl/android.html
the plugin code is here: http://terminal.jcubic.pl/js/jquery.terminal-src.js (uncommitted)
For a moment it was working but it stopped, even then I run focus and blur on textarea the keyboard don't show up. The cursor is not in textarea. The focus/blur work when I run the page on desktop Chromium.
Anybody know why textarea don't have focus?
Sometimes the cursor is inside but the keyboard don't show up and there is no that green outline. Sometime it get focus but then blur. Virtual keyboard show up only when I click inside textarea. I can't find any code that may cause this and why it was working for a moment (but not exactly I wanted).
I've try:
$('textarea').blur(function() { return false; });
or call preventDefault when I click the terminal. (the textarea is my clipboard but I want to reuse it). I keep trying different things with no success.
I've solve the issue, two things about andorid I've found. You can't delay action that trigger focus on textarea/input it need to be direct call (stack of focus call need point to html/browser native action), and it's seems that you can focus (trigger virtual keyboard) only on native events, (for instance you can't focus on load).
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. :)
I'm trying to implement a "custom" combobox options popup, so that near each option on the list i can place an icon / image.
My goal is to make this as unobtrusive as possible and make it look as close to a regular combo as possible, so, for Chrome and IE, the solution of grabbing the mouse and keyboard events that cause the standard popup to appear works fine:
#el.bind 'mousedown keydown keyup click', (e) =>
(...)
e.stopPropagation()
e.preventDefault()
This basically makes it so that the control is still there, looking native, and whenever the user clicks or focuses it, it shows up the "custom" list instead of the native one.
However, in firefox, as soon as the user clicks the combobox control (< select >), a popupshowing event is triggered, but i can't find a way to cancel it before the popup with the < options > shows up, covering up my "custom" options display implementation.
The only information regarding this event i was able to find, was on the Mozilla XUL documentation.
Thanks in advance.
I looked at the source code and it doesn't appear to be possible to cancel either the mouse event that opens the drop down or the popupshowing event (I don't even know why that event is generated). However I think you might be able to capture the mouse event on a parent element and stop its propagation.
I have an ajax script with a "get more posts" button that inserts a couple screens/viewports worth of information. In doing this, the document looses focus at some point and thus the default behavior of the space bar (page down) doesn't work in firefox.
How can I focus the document again to regain the default behavior? What components control this behavior?
It works in Chrome and IE (surprisingly), but not FF.
I tried in a callback function: document.body.focus() and document.getElementById('someClickableElement').click(), but no luck.
If I actually click on the page after the content is displayed, then I can scroll again with the space bar.
Since this is a frequently used feature, it's annoying to click "load more", click again, then space to page down.
Thoughts? Suggestions?
EDIT:
Ok, so i was using a YUI button (just a nice looking html "button" element with some css styling) for the interface. i replaced it with a link, and i no longer have this problem.
Interesting that it works as expected in Chrome & IE, and I'm not even using YUI listeners for the event (just the nice-looking buttons). It's handled by jquery's live method (b/c of the event delegation).
Also interesting that I'm not able to programmatically do what I can do physically (ie. "click").
Even if there is some YUI bug, it seems like firefox should be able to regain focus via some javascript action.
VERY WEIRD. Still any input appreciated (more javascript suggestions to try?). I'm somewhat committed to my current interface.
It looks like you need to blur YUI button element. Or do something with tab order between whole document and the YUI button.
So - not to focus() document, but to blur() YUI button.
Alternatively, you may try to apply 'keypress' event simulating 'TAB' key.
I haven't tried this but how about doing a blur() on the body or the window.
window.blur();