Can I move a DOMElement while preserving focus? - javascript

Suppose I have a simple HTML page with a textarea, and I want to wrap that textarea in a DIV. However, this doesn't always happen on startup / page load, so the user might have focus in that area, or even be typing.
I can move / wrap the area by creating a DIV, appending it to the textarea's parent, then putting the textarea inside of it, and it works great. However, when I do that, focus is removed from the textarea and if the user was in the middle of typing, they're going to get angry.
How can I move the textarea's DOM node without interrupting the user? Is this even possible?

Depending on the browser you may be able to determine which element has focus by using document.activeElement. Save the value before performing the move and then afterwards set the focus back using .focus() in the textarea is the same element as what you saved.

Well, refocusing (using focus()) is one thing, but you'll also want to keep the user's cursor at the same location (and possibly his current selection, if he's made one). It is possible though, using the document.selection/range API, see https://developer.mozilla.org/en/DOM/range .
This link describes a solution (slightly different problem) using that API in IE.

You only have to reset the focus after you move everything.
Use
.focus()
On your textArea after the move.

After appending the textarea to the div you simply have to call focus on the textarea, demonstrated in this fiddle
HTML
<textarea id="test">test</textarea>
JAVASCRIPT
var textarea = document.getElementById('test');
setTimeout(function(){
var div = document.createElement('div');
document.body.appendChild(div);
div.appendChild(textarea);
textarea.focus();
console.log('appended');
},2000);

Related

How to detect where in an input element user has clicked

Is there a way to detect where in an input element's content a user has clicked? Specifically in Firefox?
I need to know not where the caret is but where the caret would be when the user clicks into an input element.
I am trying to fix a bug in firefox where the user cannot click to place the caret into an input element which has had '.select()' called on it -- the caret fails to appear in firefox, so I want to place it manually if possible.
Thanks!
You can get the pixel position of the user's click (relative to the input field) by reading the click event's offsetX and offsetY:
// get the click position:
document.getElementById('test').onclick = function(e) {
console.log(e.offsetX, e.offsetY)
};
// for testing the 'select' issue:
document.getElementById('btn').onclick = function() {
document.getElementById('test').select();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="test">xxxxxx</textarea>
<button id="btn">Select</button>
Converting that to the desired caret location is not easy, though, because it will depend on font sizes and the text content of the input field. The best I can think of would be to do something like the technique used in textarea-caret-position, except iterating through every possible caret position in the textarea to find the one closest to where the user clicked. Which is almost certainly overkill for the task you have in mind.
(For what it's worth, the current version of firefox (v57) does not seem to have any trouble placing the caret correctly whether the input field is selected or not. I'm not certain whether this was the case in previous versions.)
Found the root of the problem, some bad css had set text-select to auto on input elements. Changing it to text-select:text allowed the fix I used for Safari to work in Firefox as well.

Replicate click inside contenteditable <div> with spellcheck

Chrome's native spell check won't work on a contenteditable <div> unless the user clicks into the <div>, which makes sense. But if I'm adding a contenteditable <div> dynamically, is there a way to replicate a user clicking into the <div>> so that the spell check will work? I tried using jQuery:
$('#div-id').click();
and
$('#div-id').trigger('click');
but these didn't work. Any help? jQuery or JavaScript works for me.
As a comment mentioned, bringing focus to the element programmatically will work to enable spellcheck. But this might be undesirable due to the focus now being changed to another element. So here is a complete solution (not using jQuery but will still work with it):
var oldFocus = document.activeElement;
div.focus();
if (oldFocus) {
oldFocus.focus();
} else {
div.blur();
}
This saves the previously focused element before focusing the div in order to enable spellcheck. Then, the focus is returned to the old element (if there was one that already had focus), otherwise it makes nothing focused.

jQuery or Javascript: detecting if the text caret has left an element?

Is there a way, via jQuery or regular Javascript, to detect if the user's text caret has moved out of an element (such as a td, div, span, etc.)?
The scenario is this: I have a table of textboxes which are grouped in pairs inside a span element. I am performing validation on the entries in the pair but I do not want validation errors to pop up until the user has switched to another pair of textboxes (i.e. another span).
Perhaps I'm going about this the wrong way, but in my mind I'm thinking perform validation on the pair once the user has switched out. But I need to know when the caret has moved over into another span element. I can't rely on the mouse position since a user could easily flick the mouse pointer to some other location while making entries.
you can use loses focus event
<input type="text" onblur="myFunction()">
or
$("input").focusout(function(){
//do Somthing;
});

Give a form field focus while out of viewport?

I'd like to be able to give a formfield (via javascript or otherwise) focus while it's out of the viewport, without having the scrollbar move to shift it into the viewport.
Is that possible?
I know & understand that it'll pop into the viewport as soon as the user starts typing - that works fine for my use case.
Simply done by creating a JavaScript function onLoad in the body tag and sending the focus to the form field doesn't matter if it's out of viewport.
HTML
<body onload="FocusMe();">
<input type="text" id="FocusTo">
JAVAscript
function FocusMe () {
document.getElementById("FocusTo").focus();
}

Manually triggering the iPhone/iPad/iPod keyboard from JavaScript

I am developing an HTML code editor using simple DIV's and capturing events. When I use this on the iPad the keyboard never pops up since i'm not technically in an editable field.
Is there a way to programatically tell the iPad that I need a keybaord?
If your code is executed via something that was initiated via a user action then it will work.
E.g;
this works (pops keyboard):
<input type='text' id='foo'><div onclick='$("#foo").focus();'>click</div>
this doesn't work (input gets a border but no keyboard pop):
<input type='text' id='foo'>
<script>
window.onload = function() {
$("#foo").focus();
}
</script>
To make the keyboard show on iOS devices you need to focus on an editable element such as an input or a textarea. Furthermore, the element must be visible and the .focus() function must to be executed in response to a user interaction such as a mouse click.
The thing is - we DON'T want the input element to be visible..
I have fiddled with this for quiet some time and eventually got the result I was looking for.
First, create an element you want to use to show the keyboard - in this case a button, and a hidden input element: (Working jsFiddle or Test on a mobile device)
<button id="openKeyboard">Open Keyboard</button>
<input id="hiddenInput" style="visibility: hidden;">
Then use the following javascript:
document.getElementById('openKeyboard').addEventListener('click', function(){
var inputElement = document.getElementById('hiddenInput');
inputElement.style.visibility = 'visible'; // unhide the input
inputElement.focus(); // focus on it so keyboard pops
inputElement.style.visibility = 'hidden'; // hide it again
});
Notes:
I have noticed that iOS safari will automatically scroll and zoom to the area of the input so make sure you use proper viewport and position your input element in a relevant location.
You can use some CSS on your input like setting the opacity, height and width to 0. However, if your input is completely hidden this won't work again, so make sure you leave the padding or border just so there's something to be rendered (even though it won't show up due to the opacity). This also means you shouldn't use display:none to hide it, hidden elements are just not allowed to be focused.
Use the regular keyboard events (keydown, keypress, keyup) on your hidden input to access the user's interaction as you would normally do. Nothing special here.
Place a transparent textarea over the contentEditable div. The keyboard will open, as soon as the user focus the textarea.
Register an event listener on the textarea for the focus event and set the visibilityof the textarea to hidden. This prevents the blinking cursor.
Set the visibility of the textarea back to visible after the blur event occurred.
Register additional event listeners for keydown, keyup, keypressevents and process theses events the same way, as you process them in the contentEditable div.
I have found that calling prompt("Enter some value") does trigger the keyboard on my iPad 2. Not sure if this is helpful in your situation or not.
The answers to this questions suggest that it's not possible: Why doesn't #contenteditable work on the iPhone?
A colleague of mine who was working on a similar project ended up using a textarea for the iPad version of his editor, and contenteditable divs/spans for browsers that support contenteditable. Perhaps something similar would work for you.
Proxy input trick
I figured out another dirty workaround, but works well.
The trick is based on the fact, that if the keyboard is already open, changing the focus will not close the keyboard.
Add a small "proxy invisible input" in top left of the page with position fixed (the fixed position prevents the flicker, also make sure that the field has font-size bigger than 16px to prevent iOS page zoom on focus)
On clicking the button, just .focus() on this invisible field. The keyboard will open...
Show or render your other input fields
Now with the keyboard open just .focus() on the desired input. You can use small setTimeout delay, for example 500ms if needed
Here's a solution for you:
<input id="my-input" type="text" />
<script type="text/javascript">
var textbox = document.getElementById('my-input');
textbox.select();
</script>

Categories