What do selectionStart and selectionEnd signify for textarea? - javascript

I came across following code snippet to insert enter into the the text in a textarea where ctrl + enter is pressed.
$("#txtChatMessage").keydown(MessageTextOnKeyEnter);
function MessageTextOnKeyEnter(e) {
console.log(this.selectionEnd);
if (e.keyCode == 13) {
if (e.ctrlKey) {
var val = this.value;
if (typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") {
var start = this.selectionStart;
this.value = val.slice(0, start) + "\n" + val.slice(this.selectionEnd);
this.selectionStart = this.selectionEnd = start + 1;
} else if (document.selection && document.selection.createRange) {
this.focus();
var range = document.selection.createRange();
range.text = "\r\n";
range.collapse(false);
range.select();
}
}
return false;
}
}
What I don't understand is what do selectionStart and selectionEnd mean here ? According to documentation that I read, selectionStart-End contain the start-end of selected text in the input element. However, here no text is explicitly selected. On doing console.log I could see that both these properties always have some value even when the text is not selected. Why is that?

selectionStart specifies the index of the selection/highlighted text within the <textarea>. Similarly, selectionEnd specifies the index where the selection ends. Initially, they are set to 0, and if the <textarea> is focused but no text is selected, the selectionStart and selectionEnd values will be the same, and reflect the position of the caret within the value of the <textarea>. On un-focus or blur of the <textarea>, they will remain at the last value that they were set to before the blur event.

Here's a fiddle you can play with:
http://jsfiddle.net/5vd8pxct/
The if block in question appears to handle cross-browser compatibility. document.selection is for IE. selectionStart and selectionEnd seem to work elsewhere. I don't have IE on my machine to experiment with it, and I'm using Chrome. It appears from my fiddle that the default start/end are 0 when the page loads. If you click into/select in the box, the start end will be as expected. If you click outside the box, the positions within the box are remembered.
document.selection is undefined in Chrome.

Your code does not work. You mix regular JavaScript and JQuery. I would suggest to start with plain JavaScript. Generally, in JavaScript this is a reference to the object on which the code will be executed.
Take a look at the following example:
<html>
<head>
<script type="text/javascript">
window.addEventListener("load", function () {
var chat = document.getElementById('txtChatMessage'); // get textarea
chat.addEventListener('keydown', function (event) { //add listener keydown for textarea
event = event || window.event;
if (event.keyCode === 13) { //return pressed?
event.preventDefault();
if (this.selectionStart != undefined) {
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var selectedText = this.value.substring(startPos, endPos);
alert("Hello, you've selected " + selectedText);
}
}
})
});
</script>
</head>
<body>
<textarea id="txtChatMessage" cols="40" rows="10"></textarea>
</body>
</html>
At first an event listener "onLoad" has been registered. Within this function we get a reference to the textarea object. On this object a new event listener "onKeyDown" has been registered. Within this function this refers to the textarea (chat) object. With the help of the event object, we can ask for the pressed key event.keyCode === 13. With this (textarea) and its attributes selectionStart and selectionEnd we get the selected text.

Related

Javascript Replace KeyPress on Input

So I was trying replace the key press "K" with "Z" in an input field.
I was successfully able to do it. But there is a slight delay which makes the user see that the "K" being changed to "Z".
This is my code:
function prinner (event)
{
document.getElementById("txx").innerHTML= event.key; //Displays key pressed on screen by changing text element.
if(event.keyCode == 32){
// User has pressed space
document.getElementById("txx").innerHTML= "Space";
}
if (event.key=="k") // Trying to replace this with z.
{
var curval = $("#namaye").val(); //namaye is the ID of the input field.
var nval = curval.slice(0,(curval.length-1))+"z";
$("#namaye").val(nval);
}
}
$("#namaye").keyup(prinner);
Does anyone know a better way to achieve this without the delay?
Use keydown instead of keyup and cancel the event so the key stroke doesn't actually get printed:
function prinner (event) {
// Displays key pressed on screen by changing text element.
document.getElementById("txx").innerHTML= event.key;
if(event.keyCode == 32){
// User has pressed space
document.getElementById("txx").innerHTML= "Space";
}
// Trying to replace this with z.
if (event.key=="k") {
var curval = $("#namaye").val(); //namaye is the ID of the input field.
var nval = curval +"z";
$("#namaye").val(nval);
// Cancel the event
event.preventDefault();
event.stopPropagation();
}
}
$("#namaye").keydown(prinner);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="namaye">
<p id="txx"></p>
Use keydown event, and cancel the default behaviour when k is pressed. Also, use selectionStart and selectionEnd properties to replace the characters that were selected at the moment the key was pressed, and to put the cursor at the right position, just after the inserted z:
function prinner (event) {
$("#txx").text(event.keyCode == 32 ? "Space" : event.key);
if (event.key=="k") {
var s = $(this).val();
var i = this.selectionStart;
s = s.substr(0, i) + "z" + s.substr(this.selectionEnd);
$(this).val(s);
this.selectionStart = this.selectionEnd = i + 1;
return false;
}
}
$("#namaye").keydown(prinner);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="namaye">
<div id="txx"></div>
Since you use jQuery, use $("#....") instead of the more verbose document.getElementById("...."). Also, in the event handler, this will be input element, so use that reference.
Try using keydown? It happens before the input is actually modified: in fact, if you return false (or e.preventDefault()) inside a keydown listener, it will actually cancel the keystroke, which I think is what you want. Then you manually add your new key. Something like (untested and skipping some details for clarity):
function prinner (event)
{
if (event.key=="k")
{
event.preventDefault() // makes sure the 'k' key never goes to the input
$("#namaye").val( $("#namaye").val() + 'z' );
}
}
$("#namaye").keyup(prinner);
You have to add an event.preventDefault() inside your if clause to stop the event propagation and then you can insert your "z" key.

window.getSelection() for contenteditable div *on click*

I have a contenteditable div and want to get the user's selection when they click a span.
My problem is that when I click the span, the selection gets unselected so window.getSelection().toString() returns ''.
How can I get this to work on click of a span?
I know the actual getSelection() works, because if I wrap window.getSelection().toString() in a setTimeout of 5 seconds, after 5 seconds, I get the selected text!
My code:
$('#btn').click(function() {
console.log(window.getSelection().toString()); //returns ''
});
#btn {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id='btn'>get selection</span>
<br><br>
<div id='ce' contenteditable='true'>test</div>
You can store the selection when there is a click on your contenteditable div, then return it when you click on the button.
document.querySelector("#ce").addEventListener(function(){
userSelection= window.getSelection().toString();
});
document.querySelector("#btn").addEventListener("mouseup",function(){
document.querySelector("#selection").innerHTML=
"You have selected:<br/><span class='selection'>" + userSelection +"</span>";
});
http://jsfiddle.net/xnvp38u3/
Since there is no event you can use to specifically detect a 'select' or 'deselect', you'll have to listen to a mouseup event and populate a "cache variable" that can store the selection in the memory:
var selection = '';
document.getElementById('ce').onmouseup = function(){
selection = window.getSelection().toString();
};
document.getElementById('btn').onclick = function(){
console.log(selection);
};
Or, provided you have jQuery, you could try this more complaint version, which also factors in keyboard-based selections:
var selection = '', shifted = false;
$('#ce').on('mouseup keyup keydown', function(e){
if (e.type === 'keydown') {
shifted = e.shiftKey;
return;
}
if (
e.type === 'mouseup' ||
(shifted && (e.keyCode === 39 || 37 || 38 || 40))
){
selection = window.getSelection().toString();
}
});
$('#btn').on('click', function(){
console.log(selection);
});

Replace char OnKeyPress

I have a textarea input element,
If the user types "#" I want to replace it with #[someTextHere].
I'm using JQuery's keypress event, but I havent been able to get what I want, I keep getting the "#" at the end of the string , I.e. [someTextHere]#.
Is it possible?
My Code:
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
</head>
<body>
<textarea id="post-txt"></textarea>
</body>
</html>
<script>
$('#post-txt').keypress(function(event){
var str = $('#post-txt').val();
if(String.fromCharCode(event.which) == '#'){
$('#post-txt').val(str.substring(0,str.length) + '[TEXT]');
}
})
</script>
Assistance would be appreciated.
that's because he adds the character after the execution of the function.you can prevent the addition of the character and add it in your code.
if(String.fromCharCode(event.which) == '#'){
event.preventDefault()
$('#post-txt').val(str + '#[TEXT]');
}
Here is a wonderful solution from kristofdegrave which takes into account selection and the cursor position.
var replacedChar = '#';
var replacement = '#[SomeTextHere]'
var moveCursorBy = replacement.length - replacedChar.length; //Or 0 if you want the cursor to be after between '#' and '[SomeTextHere]'
$('textarea').keypress(function(e){
if(e.key == replacedChar){
// IE
if(document.selection){
// Determines the selected text. If no text selected, the location of the cursor in the text is returned
var range = document.selection.createRange();
// Place the replacement on the location of the selection, and remove the data in the selection
range.text = replacement;
// Chrome + FF
} else if(this.selectionStart || this.selectionStart == '0') {
// Determines the start and end of the selection.
// If no text selected, they are the same and the location of the cursor in the text is returned
// Don't make it a jQuery obj, because selectionStart and selectionEnd isn't known.
var start = this.selectionStart;
var end = this.selectionEnd;
// Place the replacement on the location of the selection, and remove the data in the selection
$(this).val($(this).val().substring(0, start) + replacement + $(this).val().substring(end, $(this).val().length));
// Set the cursor back at the correct location in the text
this.selectionStart = start + moveCursorBy + 1;
this.selectionEnd = start + moveCursorBy + 1;
} else {
// if no selection could be determined,
// place the replacement at the end.
$(this).val($(this).val() + replacement);
}
return false;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
I took the liberty to make a jquery function out of the function posted by Alexandru Severin:
$.fn.replaceCharOnKeyPress = function(chr, replacement) {
var moveCursorBy = replacement.length - chr.length;
this.each(function() {
$(this).keypress(function(e) {
if (e.key == chr) {
// IE
if(document.selection) {
// Determines the selected text. If no text selected, the location of the cursor in the text is returned
var range = document.selection.createRange();
// Place the replacement on the location of the selection, and remove the data in the selection
range.text = replacement;
}
// Chrome + FF
else if(this.selectionStart || this.selectionStart == '0') {
// Determines the start and end of the selection.
// If no text selected, they are the same and the location of the cursor in the text is returned
// Don't make it a jQuery obj, because selectionStart and selectionEnd isn't known.
var start = this.selectionStart;
var end = this.selectionEnd;
// Place the replacement on the location of the selection, and remove the data in the selection
$(this).val($(this).val().substring(0, start) + replacement + $(this).val().substring(end, $(this).val().length));
// Set the cursor back at the correct location in the text
this.selectionStart = start + moveCursorBy + 1;
this.selectionEnd = start + moveCursorBy + 1;
}
else {
// if no selection could be determined,
// place the replacement at the end.
$(this).val($(this).val() + replacement);
}
return false;
}
});
});
return this;
};
Usage example:
$(form).find('input.price').replaceCharOnKeyPress(',', '.');
Live demo
<script type="text/javascript">
$("#input").on('input keydown paste', function() {
$(this).val($(this).val().replace(/#(?![[])/g, '#[some text]'));
var key = event.keyCode || event.charCode;
if (key == 8 || key == 46) {
this.select();
}
});
</script>
This regex **/#(?![[])/g** makes sure that only a single # is matched not #[ there by running the code only once.
This code also makes sure that even if the user pasted the # symbol they will get #[some text] in the input box.
this.select() makes sure that # will not fire again when the user tries to delete with either the backspace or delete button (when you delete '[' from '#[' the regex is no longer able to differentiate, therefore the code fires #[some text] again this is what this.select() prevents by selecting the entire #[some text] and removing it in on swoop).
Any Questions leave a comment below!
$(document).find('input').keypress(function(evt){
if(evt.which==50){
$(this).val($(this).val()+'[Letter to replace]');
evt.preventDefault();
}
});
Try this...

Refresh text input to show caret

I have the following fiddle: http://jsfiddle.net/sxAss/
By using the solution posted here I was able to move the caret to the end of the input. The problem that I have is that the input does not refresh to actually show the caret. Instead it shows the beginning of the input. What should I do to actually move the view to the end of the input. I am using Chrome.
function moveCaretToEnd(el) {
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
el.focus();
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}
First focus your input element then call your moveCaretToEnd function
like
$('#button').click(function() {
$('#input').focus();
$('#input').val($('#input').val() + 'StackOverflowTest');
moveCaretToEnd(document.getElementById('input'));
});
Working fiddle

How to set cursor at the end in a textarea?

Is there a way to set the cursor at the end in a textarea element? I'm using Firefox 3.6 and I don't need it to work in IE or Chrome. It seems all the related answers in here use onfocus() event, which seems to be useless because when user clicks on anywhere within the textarea element Firefox sets cursor position to there. I have a long text to display in a textarea so that it displays the last portion (making it easier to add something at the end).
No frameworks or libraries.
There may be many ways, e.g.
element.focus();
element.setSelectionRange(element.value.length,element.value.length);
http://jsfiddle.net/doktormolle/GSwfW/
selectionStart is enough to set initial cursor point.
element.focus();
element.selectionStart = element.value.length;
It's been a long time since I used javascript without first looking at a jQuery solution...
That being said, your best approach using javascript would be to grab the value currently in the textarea when it comes into focus and set the value of the textarea to the grabbed value. This always works in jQuery as:
$('textarea').focus(function() {
var theVal = $(this).val();
$(this).val(theVal);
});
In plain javascript:
var theArea = document.getElementByName('[textareaname]');
theArea.onFocus = function(){
var theVal = theArea.value;
theArea.value = theVal;
}
I could be wrong. Bit rusty.
var t = /* get textbox element */ ;
t.onfocus = function () {
t.scrollTop = t.scrollHeight;
setTimeout(function(){
t.select();
t.selectionStart = t.selectionEnd;
}, 10);
}
The trick is using the setTimeout to change the text insertion (carat) position after the browser is done handling the focus event; otherwise the position would be set by our script and then immediately set to something else by the browser.
Here is a function for that
function moveCaretToEnd(el) {
if (typeof el.selectionStart == "number") {
el.selectionStart = el.selectionEnd = el.value.length;
} else if (typeof el.createTextRange != "undefined") {
el.focus();
var range = el.createTextRange();
range.collapse(false);
range.select();
}
}
[Demo][Source]
textarea.focus()
textarea.value+=' ';//adds a space at the end, scrolls it into view
(this.jQuery || this.Zepto).fn.focusEnd = function () {
return this.each(function () {
var val = this.value;
this.focus();
this.value = '';
this.value = val;
});
};
#Dr.Molle answer is right. just for enhancement, U can combine with prevent-default.
http://jsfiddle.net/70des6y2/
Sample:
document.getElementById("textarea").addEventListener("mousedown", e => {
e.preventDefault();
moveToEnd(e.target);
});
function moveToEnd(element) {
element.focus();
element.setSelectionRange(element.value.length, element.value.length);
}

Categories

Resources