How to select line of text in textarea - javascript

I have a textarea that is used to hold massive SQL scripts for parsing. When the user clicks the "Parse" button, they get summary information on the SQL script.
I'd like the summary information to be clickable so that when it's clicked, the line of the SQL script is highlighted in the textarea.
I already have the line number in the output so all I need is the javascript or jquery that tells it which line of the textarea to highlight.
Is there some type of "goToLine" function? In all my searching, nothing quite addresses what I'm looking for.

This function expects first parameter to be reference to your textarea and second parameter to be the line number
function selectTextareaLine(tarea,lineNum) {
lineNum--; // array starts at 0
var lines = tarea.value.split("\n");
// calculate start/end
var startPos = 0, endPos = tarea.value.length;
for(var x = 0; x < lines.length; x++) {
if(x == lineNum) {
break;
}
startPos += (lines[x].length+1);
}
var endPos = lines[lineNum].length+startPos;
// do selection
// Chrome / Firefox
if(typeof(tarea.selectionStart) != "undefined") {
tarea.focus();
tarea.selectionStart = startPos;
tarea.selectionEnd = endPos;
return true;
}
// IE
if (document.selection && document.selection.createRange) {
tarea.focus();
tarea.select();
var range = document.selection.createRange();
range.collapse(true);
range.moveEnd("character", endPos);
range.moveStart("character", startPos);
range.select();
return true;
}
return false;
}
Usage:
var tarea = document.getElementById('myTextarea');
selectTextareaLine(tarea,3); // selects line 3
Working example:
http://jsfiddle.net/5enfp/

A somewhat neater version of the search for lines:
function select_textarea_line (ta, line_index) {
const newlines = [-1]; // Index of imaginary \n before first line
for (let i = 0; i < ta.value.length; ++i) {
if (ta.value[i] == '\n') newlines.push( i );
}
ta.focus();
ta.selectionStart = newlines[line_index] + 1;
ta.selectionEnd = newlines[line_index + 1];
} // select_textarea_line

Add a onclick or ondblclick event handler to your <textarea>:
<textarea onclick="onClickSelectLine(this)"></textarea>
And JavaScript function to handle the onclick event:
/**
* onclick event for TextArea to select the whole line
* #param textarea {HTMLTextAreaElement}
* #returns {boolean}
*/
function onClickSelectLine(textarea) {
if (typeof textarea.selectionStart == 'undefined') {
return false
}
let text = textarea.value
let before = text.substring(0, textarea.selectionStart)
let after = text.substring(textarea.selectionEnd, text.length);
let startPos = before.lastIndexOf("\n") >= 0 ? before.lastIndexOf("\n") + 1 : 0
let endPos = after.indexOf("\n") >= 0 ? textarea.selectionEnd + after.indexOf("\n") : text.length
textarea.selectionStart = startPos
textarea.selectionEnd = endPos
return true
}

To make the function more forgiving on possible faulty input add after:
// array starts at 0
lineNum--;
This code:
if (typeof(tarea) !== 'object' || typeof(tarea.value) !== 'string') {
return false;
}
if (lineNum === 'undefined' || lineNum == null || lineNum < 0) {
lineNum = 0;
}

How to select line of text in textarea javascript double click on particular line.
//This function expects first parameter to be reference to your textarea.
function ondblClickSelection(textarea){
var startPos = 0;
var lineNumber = 0;
var content = "";
if(typeof textarea.selectionStart == 'undefined') {
return false;
}
startPos = textarea.selectionStart;
endPos = textarea.value.length;
lineNumber = textarea.value.substr(0,startPos).split("\n").length - 1;
content = textarea.value.split("\n")[lineNumber];
var lines = textarea.value.split("\n");
var endPos = lines[lineNumber].length+startPos;
textarea.selectionStart = startPos;
textarea.selectionEnd = endPos;
return true;
}

Related

char counter doesn't work with paste event

I have written a code bellow for counting the character inside text box.
the code is working just fine the only problem with it is when i past a text into the text box i have to press any key so system start to count.
Could you please help me sort this problem
function GetAlhpa(text) {
var gsm = "#£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞ^{}\[~]|€ÆæßÉ!\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
var i = 0;
while (i <= String(text).length) {
if (gsm.indexOf(String(String(text).charAt(i))) == -1 && (String(text).charCodeAt(i) != 32) && (String(text).charCodeAt(i) != 27) && (String(text).charCodeAt(i) != 10) && (String(text).charCodeAt(i) != 13)) {
UniCodestring = " Unicode ";
Countsms = 70;
if ($('#SndSms_Message').val().length > 70)
Countsms = 67;
return;
}
i++;
}
Countsms = 160;
UniCodestring = "";
if ($('#SndSms_Message').val().length > 160)
Countsms = 153;
}
var Countsms = 160;
var UniCodestring = "";
var CounterSmsLen = 0;
var Two = "|^€{}[]~";
function GetCountSms() {
document.getElementById('SndSms_Message').addEventListener('input', function (e) {
var target = e.SndSms_Message,
position = SndSms_Message.selectionStart;
ConvertGreek();
CounterSmsLen = $('#SndSms_Message').val().length;
GetAlhpa($('#SndSms_Message').val());
var i = 0;
while (i < String(Two).length) {
var oldindex = -1;
while (String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i)), oldindex) > -1) {
//if ( String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i))) > -1){
CounterSmsLen += 1;
oldindex = String($('#SndSms_Message').val()).indexOf(String(String(Two).charAt(i)), oldindex) + 1;
console.log(i);
}
i++;
}
SndSms_Message.selectionEnd = position; // Set the cursor back to the initial position.
});
if ($('#SndSms_Message').val().length == 0)
CounterSmsLen = 0;
$('#SndSms_Count').html(' ' + CounterSmsLen + ' Characters' + UniCodestring + ' <br /> ' + Math.ceil(CounterSmsLen / Countsms) + ' Sms');
countsmsnumber=Math.ceil(CounterSmsLen / Countsms);
}
var greekchar = "ΑΒΕΖΗΙΚΜΝΟΡΤΥΧ";
var englishchar = "ABEZHIKMNOPTYX";
function ConvertGreek() {
var str = $('#SndSms_Message').val();
var i = 0;
while (i < String(greekchar).length) {
str = str.replace(new RegExp(String(greekchar).charAt(i), 'g'), String(englishchar).charAt(i));
i++;
}
$('#SndSms_Message').val(str);
P.S.
If i paste the number into the text box it will count it correct but if i paste character it wont count them..
You need keyup change event in order to handle paste event.
document.getElementById('SndSms_Message').addEventListener("keyup", function() {
//your code here
});
example

Modify text in a contenteditable div without resetting the caret (cursor) position

I am trying to replace any instances of /any thing in here/ with <b>/any thing in here/</b> on the fly, as changes are made in a contenteditable div.
My current implementation works, but at every keypress the caret is moved to the beginning of div making the implementation unusable. Is there some way to keep the caret position while replacing the div's contents?
$('.writer').on('keyup', function(e) {
$(this).html($(this).html().replace(/\/(.*)\//g, '<b>\/$1\/<\/b>'));
});
try it demo
$('#writer').on('keyup', function(e) {
var range = window.getSelection().getRangeAt(0);
var end_node = range.endContainer;
var end = range.endOffset;
if(end_node != this){
var text_nodes = get_text_nodes_in(this);
for (var i = 0; i < text_nodes.length; ++i) {
if(text_nodes[i] == end_node){
break;
}
end += text_nodes[i].length;
}
}
var html = $(this).html();
if(/\ $/.test(html) && $(this).text().length == end){
end = end - 1;
set_range(end,end,this);
return;
}
var filter = html.replace(/(<b>)?\/([^<\/]*)(<\/b>)?/g, '\/$2');
console.log(filter);
filter = filter.replace(/(<b>)?([^<\/]*)\/(<\/b>)?/g, '$2\/');
console.log(filter);
filter = filter.replace(/(<b>)?\/([^<\/]*)\/(<\/b>)?/g, '<b>\/$2\/<\/b>');
console.log(filter);
if(!/\ $/.test($(this).html())){
filter += ' ';
}
$(this).html(filter);
set_range(end,end,this);
});
$('#writer').on('mouseup', function(e) {
if(!/\ $/.test($(this).html())){
return;
}
var range = window.getSelection().getRangeAt(0);
var end = range.endOffset;
var end_node = range.endContainer;
if(end_node != this){
var text_nodes = get_text_nodes_in(this);
for (var i = 0; i < text_nodes.length; ++i) {
if(text_nodes[i] == end_node){
break;
}
end += text_nodes[i].length;
}
}
if($(this).text().length == end){
end = end - 1;
set_range(end,end,this);
}
});
function get_text_nodes_in(node) {
var text_nodes = [];
if (node.nodeType === 3) {
text_nodes.push(node);
} else {
var children = node.childNodes;
for (var i = 0, len = children.length; i < len; ++i) {
var text_node
text_nodes.push.apply(text_nodes, get_text_nodes_in(children[i]));
}
}
return text_nodes;
}
function set_range(start, end, element) {
var range = document.createRange();
range.selectNodeContents(element);
var text_nodes = get_text_nodes_in(element);
var foundStart = false;
var char_count = 0, end_char_count;
for (var i = 0, text_node; text_node = text_nodes[i++]; ) {
end_char_count = char_count + text_node.length;
if (!foundStart && start >= char_count && (start < end_char_count || (start === end_char_count && i < text_nodes.length))) {
range.setStart(text_node, start - char_count);
foundStart = true;
}
if (foundStart && end <= end_char_count) {
range.setEnd(text_node, end - char_count);
break;
}
char_count = end_char_count;
}
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}

mask work for id but not for class

hi i have a problem with my javascript code it works for input by id but i wat to use it on class element. I do not know what is i am doing wrong any idea? I paste my code
i want to mask time on my input
function maska(inputName, mask, evt) {
var text = document.getElementsByClassName(inputName);
try {
var value = $(text).val(); //text.value;
// Jeśli ktoś naciśnie dela lub backspace to czyszcze inputa
try {
var e = (evt.which) ? evt.which : event.keyCode;
if (e == 46 || e == 8) {
$(text).val() = ""; //text.value = "";
return;
}
} catch (e1) { }
var literalPattern = /[0\*]/;
var numberPattern = /[0-9]/;
var newValue = "";
for (var vId = 0, mId = 0; mId < mask.length; ) {
if (mId >= value.length)
break;
// Wpada jakaś inna wartość niż liczba przechowuje tylko ta dobra wartosc
if (mask[mId] == '0' && value[vId].match(numberPattern) == null) {
break;
}
// Wpadł literał
while (mask[mId].match(literalPattern) == null) {
if (value[vId] == mask[mId])
break;
newValue += mask[mId++];
}
var godzina = value.substr(0, 2);
var minuty = value.substr(3,4);
if (minuty > '59' || godzina > '23') {
break;
}
else
newValue += value[vId++];
mId++;
}
text.val() = newValue;
//text.value = newValue;
} catch (e) { }
}
getElementById returns a single DOMElement while getElementsByClass returns an array of elements. To allow for both, you could have one function that accepts a DOMElement and two functions that find the elements, one for id and one for class:
function maska(elem, mask, evt) {
try {
var value = $(elem).val();
// blah blah, rest of the function
}
function maskById(id, mask, evt) {
var element = document.getElementById(id);
maska(element, mask, evt);
}
function maskByClass(class, mask, evt) {
var element_list = document.getElementsByClass(class);
for(var i = 0; var i < element_list.length; i++) {
maska(element_list[i], mask, evt);
}
}
But you would be better off using the jquery selector combined with .each , which always returns results as a set/array, regardless of selector type.
document.getElementById returns a single element, which your code is written to handle.
document.getElementsByClassName returns multiple elements. You need to loop over them and process them each individually.
I don't get why you use getElementsByClassName and then use jQuery features?
try $('input.' + inputName)
getElementById returns a single element, while getElementsByClassName returns a collection of elements. You need to iterate over this collection
function maska(inputName, mask, evt) {
var text = document.getElementsByClassName(inputName);
try {
for (var i = 0; i < text.length; i++) {
var value = text[i].value;
// Jeśli ktoś naciśnie dela lub backspace to czyszcze inputa
try {
var e = (evt.which) ? evt.which : event.keyCode;
if (e == 46 || e == 8) {
text[i].value = "";
continue;
}
} catch (e1) { }
var literalPattern = /[0\*]/;
var numberPattern = /[0-9]/;
var newValue = "";
for (var vId = 0, mId = 0; mId < mask.length; ) {
if (mId >= value.length)
break;
// Wpada jakaś inna wartość niż liczba przechowuje tylko ta dobra wartosc
if (mask[mId] == '0' && value[vId].match(numberPattern) == null) {
break;
}
// Wpadł literał
while (mask[mId].match(literalPattern) == null) {
if (value[vId] == mask[mId])
break;
newValue += mask[mId++];
}
var godzina = value.substr(0, 2);
var minuty = value.substr(3,4);
if (minuty > '59' || godzina > '23') {
break;
}
else
newValue += value[vId++];
mId++;
}
text[i].value = newValue;
}
} catch (e) { }
}

Getting deleted character or text on pressing delete or backspace on a textbox

I have a text box, I want to get the deleted character when I press a backspace or delete key.
I have a key up event handler and i am capturing if the key is backspace. Now inside this I need to perform some tasks based on the key deleted. Please help.
After making a little tweak for the getCursorPosition function in this thread, you can get the characters deleted by tracking the current cursor selection.
The code handles the following conditions:
Type and then backspace at the end.
Move cursor in the middle of the text and delete/backspace.
Select a piece of text and then delete/backspace.
$.fn.getCursorPosition = function() {
var el = $(this).get(0);
var pos = 0;
var posEnd = 0;
if('selectionStart' in el) {
pos = el.selectionStart;
posEnd = el.selectionEnd;
} else if('selection' in document) {
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;
posEnd = Sel.text.length;
}
// return both selection start and end;
return [pos, posEnd];
};
$('#text').keydown(function (e) {
var position = $(this).getCursorPosition();
var deleted = '';
var val = $(this).val();
if (e.which == 8) {
if (position[0] == position[1]) {
if (position[0] == 0)
deleted = '';
else
deleted = val.substr(position[0] - 1, 1);
}
else {
deleted = val.substring(position[0], position[1]);
}
}
else if (e.which == 46) {
var val = $(this).val();
if (position[0] == position[1]) {
if (position[0] === val.length)
deleted = '';
else
deleted = val.substr(position[0], 1);
}
else {
deleted = val.substring(position[0], position[1]);
}
}
// Now you can test the deleted character(s) here
});
And here is Live Demo
You could use the keydown event handler instead so that the last character to be deleted is still available:
$('textarea').on('keydown',function(e) {
var deleteKeyCode = 8,
value = $(this).val(),
length = value.length,
lastChar = value.substring(length-1, length);
if (e.which === deleteKeyCode) {
alert(lastChar);
}
});
Live Demo
$('input').keydown(function(e){
$(this).data('prevVal', $(this).val());
}).keyup(function(e){
if(e.keyCode === 8) {//delete
var ele = $(this);
var val = ele.data('prevVal');
var newVal = ele.val();
var removedChar = val.substring(val.length-1);
alert(removedChar);
}
});

How to insert text into the textarea at the current cursor position?

I would like to create a simple function that adds text into a text area at the user's cursor position. It needs to be a clean function. Just the basics. I can figure out the rest.
Use selectionStart/selectionEnd properties of the input element (works for <textarea> as well)
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
}
This snippet could help you with it in a few lines of jQuery 1.9+: http://jsfiddle.net/4MBUG/2/
$('input[type=button]').on('click', function() {
var cursorPos = $('#text').prop('selectionStart');
var v = $('#text').val();
var textBefore = v.substring(0, cursorPos);
var textAfter = v.substring(cursorPos, v.length);
$('#text').val(textBefore + $(this).val() + textAfter);
});
New answer:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText
I'm not sure about the browser support for this though.
Tested in Chrome 81.
function typeInTextarea(newText, el = document.activeElement) {
const [start, end] = [el.selectionStart, el.selectionEnd];
el.setRangeText(newText, start, end, 'select');
}
document.getElementById("input").onkeydown = e => {
if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
<div>It'll replace a selection with the given text.</div>
Old answer:
A pure JS modification of Erik Pukinskis' answer:
function typeInTextarea(newText, el = document.activeElement) {
const start = el.selectionStart
const end = el.selectionEnd
const text = el.value
const before = text.substring(0, start)
const after = text.substring(end, text.length)
el.value = (before + newText + after)
el.selectionStart = el.selectionEnd = start + newText.length
el.focus()
}
document.getElementById("input").onkeydown = e => {
if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
Tested in Chrome 47, 81, and Firefox 76.
If you want to change the value of the currently selected text while you're typing in the same field (for an autocomplete or similar effect), pass document.activeElement as the first parameter.
It's not the most elegant way to do this, but it's pretty simple.
Example usages:
typeInTextarea('hello');
typeInTextarea('haha', document.getElementById('some-id'));
For the sake of proper Javascript
HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
text = text || '';
if (document.selection) {
// IE
this.focus();
var sel = document.selection.createRange();
sel.text = text;
} else if (this.selectionStart || this.selectionStart === 0) {
// Others
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
this.value = this.value.substring(0, startPos) +
text +
this.value.substring(endPos, this.value.length);
this.selectionStart = startPos + text.length;
this.selectionEnd = startPos + text.length;
} else {
this.value += text;
}
};
A simple solution that works on firefox, chrome, opera, safari and edge but probably won't work on old IE browsers.
var target = document.getElementById("mytextarea_id")
if (target.setRangeText) {
//if setRangeText function is supported by current browser
target.setRangeText(data)
} else {
target.focus()
document.execCommand('insertText', false /*no UI*/, data);
}
setRangeText function allow you to replace current selection with the provided text or if no selection then insert the text at cursor position. It's only supported by firefox as far as I know.
For other browsers there is "insertText" command which only affect the html element currently focused and has same behavior as setRangeText
Inspired partially by this article
I like simple javascript, and I usually have jQuery around. Here's what I came up with, based off mparkuk's:
function typeInTextarea(el, newText) {
var start = el.prop("selectionStart")
var end = el.prop("selectionEnd")
var text = el.val()
var before = text.substring(0, start)
var after = text.substring(end, text.length)
el.val(before + newText + after)
el[0].selectionStart = el[0].selectionEnd = start + newText.length
el.focus()
}
$("button").on("click", function() {
typeInTextarea($("textarea"), "some text")
return false
})
Here's a demo: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101
Rab's answer works great, but not for Microsoft Edge, so I added a small adaptation for Edge as well:
https://jsfiddle.net/et9borp4/
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// Microsoft Edge
else if(window.navigator.userAgent.indexOf("Edge") > -1) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)+ myValue
+ myField.value.substring(endPos, myField.value.length);
var pos = startPos + myValue.length;
myField.focus();
myField.setSelectionRange(pos, pos);
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
}
function insertAtCaret(text) {
const textarea = document.querySelector('textarea')
textarea.setRangeText(
text,
textarea.selectionStart,
textarea.selectionEnd,
'end'
)
}
setInterval(() => insertAtCaret('Hello'), 3000)
<textarea cols="60">Stack Overflow Stack Exchange Starbucks Coffee</textarea>
If the user does not touch the input after text is inserted, the 'input' event is never triggered, and the value attribute will not reflect the change. Therefore it is important to trigger the input event after programmatically inserting text. Focusing the field is not enough.
The following is a copy of Snorvarg's answer with an input trigger at the end:
function insertAtCursor(myField, myValue) {
//IE support
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// Microsoft Edge
else if(window.navigator.userAgent.indexOf("Edge") > -1) {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)+ myValue
+ myField.value.substring(endPos, myField.value.length);
var pos = startPos + myValue.length;
myField.focus();
myField.setSelectionRange(pos, pos);
}
//MOZILLA and others
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
triggerEvent(myField,'input');
}
function triggerEvent(el, type){
if ('createEvent' in document) {
// modern browsers, IE9+
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
// IE 8
var e = document.createEventObject();
e.eventType = type;
el.fireEvent('on'+e.eventType, e);
}
}
Credit to plainjs.com for the triggerEvent function
More about the oninput event at w3schools.com
I discovered this while creating an emoji-picker for a chat. If the user just select a few emojis and hit the "send" button, the input field is never touched by the user. When checking the value attribute it was always empty, even though the inserted emoji unicodes was visible in the input field. Turns out that if the user does not touch the field the 'input' event never fired and the solution was to trigger it like this. It took quite a while to figure this one out... hope it will save someone some time.
The code below is a TypeScript adaptation of the package https://github.com/grassator/insert-text-at-cursor by Dmitriy Kubyshkin.
/**
* Inserts the given text at the cursor. If the element contains a selection, the selection
* will be replaced by the text.
*/
export function insertText(input: HTMLTextAreaElement | HTMLInputElement, text: string) {
// Most of the used APIs only work with the field selected
input.focus();
// IE 8-10
if ((document as any).selection) {
const ieRange = (document as any).selection.createRange();
ieRange.text = text;
// Move cursor after the inserted text
ieRange.collapse(false /* to the end */);
ieRange.select();
return;
}
// Webkit + Edge
const isSuccess = document.execCommand("insertText", false, text);
if (!isSuccess) {
const start = input.selectionStart;
const end = input.selectionEnd;
// Firefox (non-standard method)
if (typeof (input as any).setRangeText === "function") {
(input as any).setRangeText(text);
} else {
if (canManipulateViaTextNodes(input)) {
const textNode = document.createTextNode(text);
let node = input.firstChild;
// If textarea is empty, just insert the text
if (!node) {
input.appendChild(textNode);
} else {
// Otherwise we need to find a nodes for start and end
let offset = 0;
let startNode = null;
let endNode = null;
// To make a change we just need a Range, not a Selection
const range = document.createRange();
while (node && (startNode === null || endNode === null)) {
const nodeLength = node.nodeValue.length;
// if start of the selection falls into current node
if (start >= offset && start <= offset + nodeLength) {
range.setStart((startNode = node), start - offset);
}
// if end of the selection falls into current node
if (end >= offset && end <= offset + nodeLength) {
range.setEnd((endNode = node), end - offset);
}
offset += nodeLength;
node = node.nextSibling;
}
// If there is some text selected, remove it as we should replace it
if (start !== end) {
range.deleteContents();
}
// Finally insert a new node. The browser will automatically
// split start and end nodes into two if necessary
range.insertNode(textNode);
}
} else {
// For the text input the only way is to replace the whole value :(
const value = input.value;
input.value = value.slice(0, start) + text + value.slice(end);
}
}
// Correct the cursor position to be at the end of the insertion
input.setSelectionRange(start + text.length, start + text.length);
// Notify any possible listeners of the change
const e = document.createEvent("UIEvent");
e.initEvent("input", true, false);
input.dispatchEvent(e);
}
}
function canManipulateViaTextNodes(input: HTMLTextAreaElement | HTMLInputElement) {
if (input.nodeName !== "TEXTAREA") {
return false;
}
let browserSupportsTextareaTextNodes;
if (typeof browserSupportsTextareaTextNodes === "undefined") {
const textarea = document.createElement("textarea");
textarea.value = "1";
browserSupportsTextareaTextNodes = !!textarea.firstChild;
}
return browserSupportsTextareaTextNodes;
}
Posting modified function for own reference. This example inserts a selected item from <select> object and puts the caret between the tags:
//Inserts a choicebox selected element into target by id
function insertTag(choicebox,id) {
var ta=document.getElementById(id)
ta.focus()
var ss=ta.selectionStart
var se=ta.selectionEnd
ta.value=ta.value.substring(0,ss)+'<'+choicebox.value+'>'+'</'+choicebox.value+'>'+ta.value.substring(se,ta.value.length)
ta.setSelectionRange(ss+choicebox.value.length+2,ss+choicebox.value.length+2)
}
/**
* Usage "foo baz".insertInside(4, 0, "bar ") ==> "foo bar baz"
*/
String.prototype.insertInside = function(start, delCount, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};
$('textarea').bind("keydown keypress", function (event) {
var val = $(this).val();
var indexOf = $(this).prop('selectionStart');
if(event.which === 13) {
val = val.insertInside(indexOf, 0, "<br>\n");
$(this).val(val);
$(this).focus();
}
});
Extending on Adriano's answer, we may also take cursor end into consideration which will make the "replace text" work
$('input[type=button]').on('click', function() {
var cursorStart = $('#text').prop('selectionStart');
var cursorEnd = $('#text').prop('selectionEnd');
var v = $('#text').val();
var textBefore = v.substring(0,cursorStart);
var textAfter = v.substring(cursorEnd);
$('#text').val(textBefore + $(this).val() + textAfter);
});
Changed it to getElementById(myField):
function insertAtCursor(myField, myValue) {
// IE support
if (document.selection) {
document.getElementById(myField).focus();
sel = document.selection.createRange();
sel.text = myValue;
}
// MOZILLA and others
else if (document.getElementById(myField).selectionStart || document.getElementById(myField).selectionStart == '0') {
var startPos = document.getElementById(myField).selectionStart;
var endPos = document.getElementById(myField).selectionEnd;
document.getElementById(myField).value =
document.getElementById(myField).value.substring(0, startPos)
+ myValue
+ document.getElementById(myField).value.substring(endPos, document.getElementById(myField).value.length);
} else {
document.getElementById(myField).value += myValue;
}
}

Categories

Resources