I have a page with a lot of textboxes. When someone clicks a link, i want a word or two to be inserted where the cursor is, or appended to the textbox which has the focus.
For example, if the cursor/focus is on a textbox saying 'apple' and he clicks a link saying '[email]', then i want the textbox to say, 'apple bob#example.com'.
How can I do this? Is this even possible, since what if the focus is on a radio/dropdown/non textbox element? Can the last focused on textbox be remembered?
Use this, from here:
function insertAtCaret(areaId, text) {
var txtarea = document.getElementById(areaId);
if (!txtarea) {
return;
}
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : (document.selection ? "ie" : false));
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
strPos = range.text.length;
} else if (br == "ff") {
strPos = txtarea.selectionStart;
}
var front = (txtarea.value).substring(0, strPos);
var back = (txtarea.value).substring(strPos, txtarea.value.length);
txtarea.value = front + text + back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var ieRange = document.selection.createRange();
ieRange.moveStart('character', -txtarea.value.length);
ieRange.moveStart('character', strPos);
ieRange.moveEnd('character', 0);
ieRange.select();
} else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
<textarea id="textareaid"></textarea>
Click Here to Insert
Maybe a shorter version, would be easier to understand?
jQuery("#btn").on('click', function() {
var $txt = jQuery("#txt");
var caretPos = $txt[0].selectionStart;
var textAreaTxt = $txt.val();
var txtToAdd = "stuff";
$txt.val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<textarea id="txt" rows="15" cols="70">There is some text here.</textarea>
<input type="button" id="btn" value="OK" />
I wrote this in response to How to add a text to a textbox from the current position of the pointer with jquery?
The approved answer from George Claghorn worked great for simply inserting text at the cursor position. If the user had selected text though, and you want that text to be replaced (the default experience with most text), you need to make a small change when setting the 'back' variable.
Also, if you don't need to support older versions of IE, modern versions support textarea.selectionStart, so you can take out all of the browser detection, and IE-specific code.
Here is a simplified version that works for Chrome and IE11 at least, and handles replacing selected text.
function insertAtCaret(areaId, text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var caretPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0, caretPos);
var back = (txtarea.value).substring(txtarea.selectionEnd, txtarea.value.length);
txtarea.value = front + text + back;
caretPos = caretPos + text.length;
txtarea.selectionStart = caretPos;
txtarea.selectionEnd = caretPos;
txtarea.focus();
txtarea.scrollTop = scrollPos;
}
The code above didn't work for me in IE. Here's some code based on this answer.
I took out the getElementById so I could reference the element in a different way.
function insertAtCaret(element, text) {
if (document.selection) {
element.focus();
var sel = document.selection.createRange();
sel.text = text;
element.focus();
} else if (element.selectionStart || element.selectionStart === 0) {
var startPos = element.selectionStart;
var endPos = element.selectionEnd;
var scrollTop = element.scrollTop;
element.value = element.value.substring(0, startPos) +
text + element.value.substring(endPos, element.value.length);
element.focus();
element.selectionStart = startPos + text.length;
element.selectionEnd = startPos + text.length;
element.scrollTop = scrollTop;
} else {
element.value += text;
element.focus();
}
}
input{width:100px}
label{display:block;margin:10px 0}
<label for="in2copy">Copy text from: <input id="in2copy" type="text" value="x"></label>
<label for="in2ins">Element to insert: <input id="in2ins" type="text" value="1,2,3" autofocus></label>
<button onclick="insertAtCaret(document.getElementById('in2ins'),document.getElementById('in2copy').value)">Insert</button>
EDIT: Added a running snippet, jQuery is not being used.
using #quick_sliv answer:
function insertAtCaret(el, text) {
var caretPos = el.selectionStart;
var textAreaTxt = el.value;
el.value = textAreaTxt.substring(0, caretPos) + text + textAreaTxt.substring(caretPos);
};
How to insert some Text to current cursor position of a TextBox through JQuery and JavaScript
Process
Find the Current Cursor Position
Get the Text to be Copied
Set the Text Over there
Update the Cursor position
Here I have 2 TextBoxes and a Button. I have to Click on a certain position on a textbox and then click on the button to paste the text from the
other textbox to the the position of the previous textbox.
Main issue here is that getting the current cursor position where we will paste the text.
//Textbox on which to be pasted
<input type="text" id="txtOnWhichToBePasted" />
//Textbox from where to be pasted
<input type="text" id="txtFromWhichToBePasted" />
//Button on which click the text to be pasted
<input type="button" id="btnInsert" value="Insert"/>
<script type="text/javascript">
$(document).ready(function () {
$('#btnInsert').bind('click', function () {
var TextToBePasted = $('#txtFromWhichToBePasted').value;
var ControlOnWhichToBePasted = $('#txtOnWhichToBePasted');
//Paste the Text
PasteTag(ControlOnWhichToBePasted, TextToBePasted);
});
});
//Function Pasting The Text
function PasteTag(ControlOnWhichToBePasted,TextToBePasted) {
//Get the position where to be paste
var CaretPos = 0;
// IE Support
if (document.selection) {
ControlOnWhichToBePasted.focus();
var Sel = document.selection.createRange();
Sel.moveStart('character', -ctrl.value.length);
CaretPos = Sel.text.length;
}
// Firefox support
else if (ControlOnWhichToBePasted.selectionStart || ControlOnWhichToBePasted.selectionStart == '0')
CaretPos = ControlOnWhichToBePasted.selectionStart;
//paste the text
var WholeString = ControlOnWhichToBePasted.value;
var txt1 = WholeString.substring(0, CaretPos);
var txt2 = WholeString.substring(CaretPos, WholeString.length);
WholeString = txt1 + TextToBePasted + txt2;
var CaretPos = txt1.length + TextToBePasted.length;
ControlOnWhichToBePasted.value = WholeString;
//update The cursor position
setCaretPosition(ControlOnWhichToBePasted, CaretPos);
}
function setCaretPosition(ControlOnWhichToBePasted, pos) {
if (ControlOnWhichToBePasted.setSelectionRange) {
ControlOnWhichToBePasted.focus();
ControlOnWhichToBePasted.setSelectionRange(pos, pos);
}
else if (ControlOnWhichToBePasted.createTextRange) {
var range = ControlOnWhichToBePasted.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
</script>
Adding text to current cursor position involves two steps:
Adding the text at the current cursor position
Updating the current cursor position
Demo: https://codepen.io/anon/pen/qZXmgN
Tested in Chrome 48, Firefox 45, IE 11 and Edge 25
JS:
function addTextAtCaret(textAreaId, text) {
var textArea = document.getElementById(textAreaId);
var cursorPosition = textArea.selectionStart;
addTextAtCursorPosition(textArea, cursorPosition, text);
updateCursorPosition(cursorPosition, text, textArea);
}
function addTextAtCursorPosition(textArea, cursorPosition, text) {
var front = (textArea.value).substring(0, cursorPosition);
var back = (textArea.value).substring(cursorPosition, textArea.value.length);
textArea.value = front + text + back;
}
function updateCursorPosition(cursorPosition, text, textArea) {
cursorPosition = cursorPosition + text.length;
textArea.selectionStart = cursorPosition;
textArea.selectionEnd = cursorPosition;
textArea.focus();
}
HTML:
<div>
<button type="button" onclick="addTextAtCaret('textArea','Apple')">Insert Apple!</button>
<button type="button" onclick="addTextAtCaret('textArea','Mango')">Insert Mango!</button>
<button type="button" onclick="addTextAtCaret('textArea','Orange')">Insert Orange!</button>
</div>
<textarea id="textArea" rows="20" cols="50"></textarea>
I think you could use the following JavaScript to track the last-focused textbox:
<script>
var holdFocus;
function updateFocus(x)
{
holdFocus = x;
}
function appendTextToLastFocus(text)
{
holdFocus.value += text;
}
</script>
Usage:
<input type="textbox" onfocus="updateFocus(this)" />
<a href="#" onclick="appendTextToLastFocus('textToAppend')" />
A previous solution (props to gclaghorn) uses textarea and calculates the position of the cursor too, so it may be better for what you want. On the other hand, this one would be more lightweight, if that's what you're looking for.
This question's answer was posted so long ago and I stumbled upon it via a Google search. HTML5 provides the HTMLInputElement API that includes the setRangeText() method, which replaces a range of text in an <input> or <textarea> element with a new string:
element.setRangeText('abc');
The above would replace the selection made inside element with abc. You can also specify which part of the input value to replace:
element.setRangeText('abc', 3, 5);
The above would replace the 4th till 6th characters of the input value with abc. You can also specify how the selection should be set after the text has been replaced by providing one of the following strings as the 4th parameter:
'preserve' attempts to preserve the selection. This is the default.
'select' selects the newly inserted text.
'start' moves the selection to just before the inserted text.
'end' moves the selection to just after the inserted text.
Browser compatibility
The MDN page for setRangeText doesn't provide browser compatibility data, but I guess it'd be the same as HTMLInputElement.setSelectionRange(), which is basically all modern browsers, IE 9 and above, Edge 12 and above.
The accepted answer didn't work for me on Internet Explorer 9.
I checked it and the browser detection was not working properly, it detected ff (firefox) when i was at Internet Explorer.
I just did this change:
if ($.browser.msie)
Instead of:
if (br == "ie") {
The resulting code is this one:
function insertAtCaret(areaId,text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : (document.selection ? "ie" : false ) );
if ($.browser.msie) {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
strPos = range.text.length;
}
else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0,strPos);
var back = (txtarea.value).substring(strPos,txtarea.value.length);
txtarea.value=front+text+back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
range.moveStart ('character', strPos);
range.moveEnd ('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
This jQuery plugin gives you a pre-made way of selection/caret manipulation.
you can only focus required textbox an insert the text there. there is no way to find out where focus is AFAIK (maybe interating over all DOM nodes?).
check this stackoverflow - it has a solution for you:
How do I find out which DOM element has the focus?
Content Editable, HTML or any other DOM element Selections
If you are trying to insert at caret on a <div contenteditable="true">, this becomes much more difficult, especially if there are children within the editable container.
I have had really great luck using the Rangy library:
GIT: https://github.com/timdown/rangy
NPM: https://www.npmjs.com/package/rangy
It has a ton of great features such as:
Save Position or Selection
Then later, Restore the Position or Selection
Get selection HTML or Plaintext
Among many others
The online demo was not working last I checked, however the repo has working demos. To get started, simple download the Repo from Git or NPM, then open ./rangy/demos/index.html
It makes working with caret pos and text selection a breeze!
Related
I am working on a markdown editor in HTML and JS, which previously used textarea but I started moving it to a contenteditable div recently due to the limitations it had, tried a lot but I cannot get it working, I just need a basic function to insert markdown ** around a selection, but there seems to be something wrong with contenteditable divs, anyone has any idea how to fix?
function editorInsertFormatting(txtarea, text) {
var selectStart = txtarea.selectionStart;
var selectEnd = txtarea.selectionEnd;
var scrollPos = txtarea.scrollTop;
var caretPos = txtarea.selectionStart;
var front = txtarea.value.substring(0, caretPos);
var back = txtarea.value.substring(
txtarea.selectionEnd,
txtarea.value.length
);
var middle = txtarea.value.substring(caretPos, txtarea.selectionEnd);
txtarea.value = front + text + middle + text + back;
if (selectStart !== selectEnd) {
txtarea.selectionStart = selectStart + text.length;
txtarea.selectionEnd = selectEnd + text.length;
} else {
txtarea.selectionStart = selectStart + text.length;
txtarea.selectionEnd = txtarea.selectionStart;
}
txtarea.focus();
txtarea.scrollTop = scrollPos;
editorLiveParser();
}
Take a look at window.getSelection(), selection.getRangeAt(), and document.execCommand, but it's a very big mountain you're going to climb.
Here's a simple starting point...
var sel = window.getSelection();
var range = sel.getRangeAt(0);
var range0 = range.cloneRange();
range.collapse(true);
document.execCommand('insertText', false, '!!!START!!!');
sel.removeAllRanges();
sel.addRange(range0);
range0.collapse(false);
document.execCommand('insertText', false, '!!!END!!!');
See https://jsfiddle.net/Abeeee/o0e481q3/1/ for a running example
I have a text area that users can fill out on my website. Here is an example of what I want to do:
When users comment on other people's posts in this text area, they have a collection of emoji pictures at the top to select. I want the users to click on an emoji they want to choose (and then a border appear around it), then the user can click once in the text area where they would like text pasted. This text will be from the image's alt attribute. This saves the user time when writing emoji character codes.
I have attempted some of the code myself, but I am not sure about the JavaScript. Here is my attempt...
My CSS...
img:hover {
border:1px solid blue
}
And my HTML...
<img src="smiley1.png" alt="{smiley001}"><img src="smiley2.png" alt="{smiley002}"><img src="smiley3.png" alt="{smiley003}"><img src="smiley4.png" alt="{smiley004}"><img src="smiley5.png" alt="{smiley005}"><br>
<textarea id="comments" cols="50" rows="10"></textarea>
Is there a javascript/jquery solution to this?
If this is not possible, is there a way to do it with text instead of images, with the title attribute being copied to the textarea?
Check out this fiddle. I found an "insert at the mouse location" function from this question.
The rest is simple. Add a click event to save the alt attribute of whatever image the you clicked and another click event to the textarea so the alt code is inserted. It's just a matter of clicking the image and then clicking where you want the alt code to show up.
selected = '';
$('img').click(function(){
console.log($(this).attr('alt'));
selected = $(this).attr('alt');
});
$('#comments').click(function(){
insertAtCaret('comments',selected)
// Clear the selection so it isn't copied repeatedly
selected = '';
});
// Copied from the linked answer
function insertAtCaret(areaId,text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
"ff" : (document.selection ? "ie" : false ) );
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
strPos = range.text.length;
}
else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0,strPos);
var back = (txtarea.value).substring(strPos,txtarea.value.length);
txtarea.value=front+text+back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
range.moveStart ('character', strPos);
range.moveEnd ('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
The basic javascript code should be something like:
function write_tag() {
var text = this.getAttribute("alt");
getElementById("textarea").innerHTML += text;
}
In this case, the text would be added at the end of the textarea content. A more complex code should check where is the cursor and attempt to insert the text into that point of the string.
The listener that triggers the function can be added in the image tag:
<img src="smiley1.png" alt="{smiley001}" onclick="write_tag()">
It would be cleaner to add the listener programatically, but it's another story: You should decide if you will have the javascript in the page or an external one, in that case you should wait for the entire page to load and then add listeners for all images. If you use jQuery, you can write something like this, assuming you have all your emojis into a div with the class "emojis":
$(document).ready(function(){
$(".emojis img").bind("click",write_tag);
}
var front = (txtarea.value).substring(0,strPos);
var back = (txtarea.value).substring(strPos,txtarea.value.length);
txtarea.value=front+text+back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart ('character', -txtarea.value.length);
range.moveStart ('character', strPos);
range.moveEnd ('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
The default behaviour in browsers is to select the next form element. I want my textbox to indent code by, lets say 4 spaces when tab is pressed. Just like if you were indenting code in an IDE. How would I achieve this behaviour in JavaScript? If I have to use jQuery, or its easier, I'm fine with that.
Thanks!
Tracking the key code and adding 4 spaces to the element should do it. You can prevent the default when the tab key is pressed. Like so?:
Edit after all comments:
Ahh, ok so you're actually asking for several JS functions (get cursor position in text area, change text, set cursor position in text area). A little more looking around would have given you all of these, but since I'm a nice guy I'll put it in there for ya. The other answers can be found in this post about getCursorPosition() and this post about setCursorPosition(). I updated the jsFiddle for ya. Here's the code update
<script>
$('#myarea').on('keydown', function(e) {
var thecode = e.keyCode || e.which;
if (thecode == 9) {
e.preventDefault();
var html = $('#myarea').val();
var pos = $('#myarea').getCursorPosition(); // get cursor position
var prepend = html.substring(0,pos);
var append = html.replace(prepend,'');
var newVal = prepend+' '+append;
$('#myarea').val(newVal);
$('#myarea').setCursorPosition(pos+4);
}
});
new function($) {
$.fn.getCursorPosition = function() {
var pos = 0;
var el = $(this).get(0);
// IE Support
if (document.selection) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
// Firefox support
else if (el.selectionStart || el.selectionStart == '0')
pos = el.selectionStart;
return pos;
}
} (jQuery);
new function($) {
$.fn.setCursorPosition = function(pos) {
if ($(this).get(0).setSelectionRange) {
$(this).get(0).setSelectionRange(pos, pos);
} else if ($(this).get(0).createTextRange) {
var range = $(this).get(0).createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
}(jQuery);
</script>
<textarea id="myarea"></textarea>
I need to get the user selected area of a textarea and then insert <a> tags round it.
I use this to get the user selected area:
var textComponent = document.getElementById('article');
var selectedText;
if (document.selection != undefined)
{
textComponent.focus();
var sel = document.selection.createRange();
selectedText = sel.text;
}
// Mozilla version
else if (textComponent.selectionStart != undefined)
{
var startPos = textComponent.selectionStart;
var endPos = textComponent.selectionEnd;
selectedText = textComponent.value.substring(startPos, endPos)
}
Now, I know I can do a string search for the user selected text and insert a tags round it, but what happens if that user selected text appears twice in the text, for example.
Hello to you, goodbye to you.
If the user highlights the second 'you' for the link they want, surely a string replace would put a tags around every instance of 'you'.
Whats the best way to do this?
You could use my jQuery plug-in for this (demo):
$("#article").surroundSelectedText('', "");
Alternatively you could use the getInputSelection() function that I've posted on Stack Overflow a few times to get the selection start and end character indices in all major browsers and then do string substitution on the textarea's value:
var sel = getInputSelection(textComponent);
var val = textComponent.value;
textComponent.value = val.slice(0, sel.start) +
'<a href="foo.html">' +
val.slice(sel.start, sel.end) +
"</a>" +
val.slice(sel.end);
Why capture the selected text at all? What you really want is the start/end positions to drop in tags.
var textComponent = document.getElementById('article');
var selectedText;
var startPos;
var endPos;
// the easy way
if (textComponent.selectionStart != undefined)
{
startPos = textComponent.selectionStart;
endPos = textComponent.selectionEnd;
}
// the hard way
else if (document.selection != undefined)
{
textComponent.focus();
var sel = document.selection.createRange();
var range = document.selection.createRange();
var stored_range = range.duplicate();
stored_range.moveToElementText(textComponent);
stored_range.setEndPoint( 'EndToEnd', range );
startPos = stored_range.text.length - range.text.length;
endPos = startPos + range.text.length;
}
// add in tags at startPos and endPos
var val = textComponent.value;
textComponent.value = val.substring(0, startPos) + "<a>" + val.substring(startPos, endPos) + "</a>" + val.substring(endPos);
IE code modified from this reference.
EDIT: Note Tim Down's comment about newlines. Also, probably use his soltion, because it's better.
I'm trying to insert the image url where the point of the is to be when editing the textarea value.
function addImageURL()
{
var imageurl = prompt("Enter image URL", "Your name")
var post = document.getElementById("message-put").value;
document.getElementById('message-put').value = post + '[img]' + imageurl + '[/img]';
}
This code grabs the value inside the adds the image url next to it which I don't want, I need it to insert it where the point was when editing the textarea
Thanks
EDIT:
Like Stackoverflow, you see the image icon, you click it or click on the hyperlink, a box comes up and inserts it where you were editing the textarea :P
If you want to insert something at the cursor, here is something I found using teh Googlez:
function insertAtCaret(areaId, text) {
var txtarea = document.getElementById(areaId);
var scrollPos = txtarea.scrollTop;
var strPos = 0;
var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ? "ff" : (document.selection ? "ie" : false ) );
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
strPos = range.text.length;
} else if (br == "ff") strPos = txtarea.selectionStart;
var front = (txtarea.value).substring(0, strPos);
var back = (txtarea.value).substring(strPos, txtarea.value.length);
txtarea.value = front + text + back;
strPos = strPos + text.length;
if (br == "ie") {
txtarea.focus();
var range = document.selection.createRange();
range.moveStart('character', -txtarea.value.length);
range.moveStart('character', strPos);
range.moveEnd('character', 0);
range.select();
}
else if (br == "ff") {
txtarea.selectionStart = strPos;
txtarea.selectionEnd = strPos;
txtarea.focus();
}
txtarea.scrollTop = scrollPos;
}
The source: http://www.scottklarr.com/topic/425/how-to-insert-text-into-a-textarea-where-the-cursor-is/ (I haven't tested this; it's from 2008 so it may be a little dated).
A technique I used when trying to achieve similar functionality in a WYSIWYG:
Retrieve parent node from selection (range) in Gecko and Webkit » StackOverflow
Might be useful if working with frames, or want to avoid some cursor issues I ran into.
I think you may find what you're looking for here:
Caret position in textarea, in characters from the start
And an example implementation here:
http://javascript.nwbox.com/cursor_position/