how to get caret position in textarea - javascript

JS
function doGetCaretPosition (ctrl)
{
var CaretPos = 0;
// IE Support
if (document.selection)
{
ctrl.focus ();
var Sel = document.selection.createRange ();
Sel.moveStart ('character', -ctrl.value.length);
CaretPos = Sel.text.length;
}
// Firefox support
else if (ctrl.selectionStart || ctrl.selectionStart == '0')
{
CaretPos = ctrl.selectionStart;
}
return (CaretPos);
}
window.onload=function(){
editor = CKEDITOR.replace('content');
}
HTML:
<body>
<form name="inForm" method="post">
<textarea id="content" name="content" cols="100%" rows="10">1234dfgdf5</textarea>
<br>
<input type="button" onclick="alert(doGetCaretPosition(document.getElementById('content')));"
value="Get Position">
</form>
</body>
Why "Get Position" and click it to continue zeros is coming?

Related

how to get the correct caret position

I'm making a contenteditable based input and I want to add emoticon support
i have the contenteditable div, and inside is only text and IMG_TAG for emoticons. On blur, I want to save the caret position. And when I click to open the emoticon box to focus the contenteditable and set the caret where it was. Something to simulate web.whatsapp.com behaviour
I've found this piece of code
function getCaretCharacterOffsetWithin(element) {
var caretOffset = 0;
var doc = element.ownerDocument || element.document;
var win = doc.defaultView || doc.parentWindow;
var sel;
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
But it does not give me the correct position.
"hello IMG_TAG john". If the cursor is just before the IMG_TAG -> the position is 6, which is correct, but if it is just after the IMG_TAG is still 6.
Also, I didn't find a good "setCaretPosition" function to work well for me.
I've been searching for two hours now. Anyone got a good answer ?
In the demo we have used the Selection and Range APIs for for setting and gettingšŸ—” the caret's position. Since the OP needs to find a caret's position, we will concentrate on the getCaret() function:
var btn2 = document.getElementById('btn2');
btn2.addEventListener('click', getCaret, false);
function getCaret() {
var sel = window.getSelection();
var end = sel.focusOffset;
var out1 = document.getElementById('out1');
out1.textContent = end;
}
The function references the Selection object
Then you store the Selection object's property, focusOffset
focusOffset will give us an integer representing the number of characters there are between it (focusNode) and the beginning of the Selection (anchorNode). If the Selection contains an element, then it includes the element's childNodes into the count as well.
When testing the getCaret() function, just select some text, then click the Get Focus button, the result is displayed next to the area labeled Caret Position:
SNIPPET
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<style>
fieldset {
margin: 20px auto;
}
input {
width: 5ex;
text-align: center;
padding: 1px 3px;
}
</style>
</head>
<body>
<div id="editor1" contenteditable="true">
<br/>123456789abcdefghijklmnopqrstuvwxyz
<br/>12 45678 abcd fg ijk mnopqrst vwxyz
<br/>123 5 789a cde ghijklm o qrst v xyz
<br/>12345 789abcd fg ijklmnopq s u wxyz
<br/>123 567 9abc efg ijklm op rst vwxy
<br/>1 34 6789a cdef hij lm opq stuvwxyz
<br/>1 3456 89a cd fghij l no qrst vwx z
<br/>12 4 6789 bcd fgh j lmno q stuv xy
</div>
<fieldset>
<input type="button" class="fontStyle" onclick="document.execCommand('italic',false,null);" value="I" title="Italicize Highlighted Text">
<input type="button" class="fontStyle" onclick="document.execCommand('bold',false,null);" value="B" title="Bold Highlighted Text">
<input id="row" name="row" placeholder="Row#" />
<input id="col" name="col" placeholder="Col#" />
<button id="btn1">Set Focus</button>
<button id="btn2">Get Focus</button>
<label for='out1'>Caret Position:</label>
<output id="out1"></output>
</fieldset>
<p>Each row has a number of non-repeated string of alphanumeric characters:</p>
<pre><code>123456789abcdefghijklmnopqrstuvwxyz</code></pre>
<p>Maximum of 35 characters. Every row except the first row has some missing characters and in their place is a whitespace.
</p>
<script>
function setCaret(x, y) {
var ele = document.getElementById("editor1");
var rng = document.createRange();
var sel = window.getSelection();
var row = parseInt(x, 10) * 2;
var col = parseInt(y, 10);
rng.setStart(ele.childNodes[row], col);
rng.collapse(true);
sel.removeAllRanges();
sel.addRange(rng);
ele.focus();
}
function getCaret() {
var sel = window.getSelection();
var end = sel.focusOffset;
var out1 = document.getElementById('out1');
out1.textContent = end;
}
var btn2 = document.getElementById('btn2');
var btn1 = document.getElementById('btn1');
btn1.addEventListener('click', function(event) {
var rowSet = document.getElementById('row').value;
var colSet = document.getElementById('col').value;
setCaret(rowSet, colSet);
}, true);
btn2.addEventListener('click', getCaret, false);
</script>
</body>
</html>
šŸ—”Just figured it out after trying to remember how setCaret() function worked.

Get and set cursor position with contenteditable div

I have a contenteditable div which I would like to be able to have users insert things such as links, images or YouTube videos. At the moment this is what I have:
function addLink() {
var link = $('#url').val();
$('#editor').focus();
document.execCommand('createLink', false, link);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Text Editor -->
<div id="editor" contenteditable="true"></div>
<!-- Add Link -->
<input type="text" id="url">
<button onclick="addLink()">Submit</button>
As you can see, the user has to type into a separate text box to enter the link address. As a result, when the link is added to the editor, it is not added to the position that the pointer/caret was on.
My question is how I can get and set the location of the pointer/caret. I have seen other questions such as this for setting the pointer however I would prefer to have a solution which is supported in all modern browsers, including Chrome, Safari, Firefox and IE9+.
Any ideas? Thanks.
Edit:
I found the code below which gets the position however, it only gets the position according to the line it is on. For example if I had this (where | is the cursor):
This is some text
And som|e more text
Then I would be returned the value 7, not 24.
function getPosition() {
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt) {
return sel.getRangeAt(0).startOffset;
}
}
return null;
}
There's a ton of related info onsite. This one works for me and my clients.
DEMO
https://stackoverflow.com/a/6249440/2813224
function setCaret(line, col) {
var ele = document.getElementById("editable");
var rng = document.createRange();
var sel = window.getSelection();
rng.setStart(ele.childNodes[line], col);
rng.collapse(true);
sel.removeAllRanges();
sel.addRange(rng);
ele.focus();
}
//https://stackoverflow.com/a/6249440/2813224
var line = document.getElementById('ln').value;
var col = document.getElementById('cl').value;
var btn = document.getElementById('btn');
btn.addEventListener('click', function(event) {
var lineSet = parseInt(line, 10);
var colSet = parseInt(col, 10);
setCaret(lineSet, colSet);
}, true);
<div id="editable" contenteditable="true">
<br/>text text text text text text
<br/>text text text text text text
<br/>text text text text text text
<br/>
<br/>
</div>
<fieldset>
<button id="btn">focus</button>
<input type="button" class="fontStyle" onclick="document.execCommand('italic',false,null);" value="I" title="Italicize Highlighted Text">
<input type="button" class="fontStyle" onclick="document.execCommand('bold',false,null);" value="B" title="Bold Highlighted Text">
<input id="ln" placeholder="Line#" />
<input id="cl" placeholder="Column#" />
</fieldset>
A good rich-text editor is one of the harder things to do currently, and is pretty much a project by itself (unfriendly API, huge number of corner cases, cross-browser differences, the list goes on). I would strongly advise you to try and find an existing solution.
Some libraries that can be used include:
Quill (http://quilljs.com)
WYSGIHTML (http://wysihtml.com)
CodeMirror library (http://codemirror.net)
I have tried to find a solution,
With a little help it can be perfected.
It is a combination of answers I've found on SO, and my exp.
Its tricky, its messy... but if you must, you can use it but it requires a bit of work to support inner links (if you cursor is on an anchor it will create anchor inside anchor)
Here's the JS:
var lastPos;
var curNode = 0;
function setCaret() {
curNode=0;
var el = document.getElementById("editor");
var range = document.createRange();
var sel = window.getSelection();
console.log(el.childNodes);
if (el.childNodes.length > 0) {
while (lastPos > el.childNodes[curNode].childNodes[0].textContent.length) {
lastPos = lastPos - el.childNodes[curNode].childNodes[0].textContent.length;
curNode++;
}
range.setStart(el.childNodes[curNode].childNodes[0], lastPos);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
el.focus();
};
function savePos() {
lastPos = getCaretCharacterOffsetWithin(document.getElementById('editor'));
}
function addLink() {
console.log(lastPos);
setCaret();
console.log(getCaretCharacterOffsetWithin(document.getElementById('editor')));
console.log('focus');
// $("#editor").focus();
var link = $('#url').val();
document.execCommand('createLink', false, link);
}
function getCaretCharacterOffsetWithin(element) {
var caretOffset = 0;
var doc = element.ownerDocument || element.document;
var win = doc.defaultView || doc.parentWindow;
var sel;
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
} else if ((sel = doc.selection) && sel.type != "Control") {
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
fiddle
This is what you asked for, in your bounty: on the following example you can see how to detect the exact number of characters of the actual point where you clicked the mouse on:
<!-- Text Editor -->
<div id="editor" class="divClass" contenteditable="true">type here some text</div>
<script>
document.getElementById("editor").addEventListener("mouseup", function(key) {
alert(getCaretCharacterOffsetWithin(document.getElementById("editor")));
}, false);
function getCaretCharacterOffsetWithin(element) {
var caretOffset = 0;
var doc = element.ownerDocument || element.document;
var win = doc.defaultView || doc.parentWindow;
var sel;
if (typeof win.getSelection != "undefined") {
sel = win.getSelection();
if (sel.rangeCount > 0) {
var range = win.getSelection().getRangeAt(0);
var preCaretRange = range.cloneRange();
preCaretRange.selectNodeContents(element);
preCaretRange.setEnd(range.endContainer, range.endOffset);
caretOffset = preCaretRange.toString().length;
}
} else if ( (sel = doc.selection) && sel.type != "Control") {
var textRange = sel.createRange();
var preCaretTextRange = doc.body.createTextRange();
preCaretTextRange.moveToElementText(element);
preCaretTextRange.setEndPoint("EndToEnd", textRange);
caretOffset = preCaretTextRange.text.length;
}
return caretOffset;
}
</script>
I found a problem with emojis. Emojis have a length which is more than 1.
I solved it.
<script>
function getCursorPosition() {
if(window.getSelection()){
var sel = window.getSelection();
if(sel.getRangeAt){
var pos = sel.getRangeAt(0).startOffset;
var endPos = pos + Array.from(editor.innerHTML.slice(0,pos)).length - editor.innerHTML.slice(0,pos).split("").length;
return endPos;
}
}
return null;
}
var editor = document.querySelector("#editor");
var output = document.querySelector("#output");
editor.addEventListener("input",function(){
output.innerHTML = "Selection: " + getCursorPosition();
});
</script>
<div contenteditable id="editor">text</div>
<div id="output">Selection:</div>

3 textboxes, 1 button, on button click put text in the textbox where the cursor is

I have 3 textboxes and a button, what I need to do is that on the button click I want text to appear in which ever textbox the cursor is located.
I can do it for one textbox but for 3 different I need 3 different buttons.
Can you plz help me do it using just one button???
Plz help..
This is what I have accomplished for 1 textbox:
function insertAtCaret(areaId, embedctrl) {
var text = document.getElementById(embedctrl).value;
if (text != "-1") {
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;
}
}
In the above eg, the dropdown's(embedctrl) selectedvalue gets inserted at cursor position in a textbox.
Part 2:
I tried the following using a dropdownlist to insert text in the textboxes but it doesnt work. Any insights so as to why???
<script type="text/javascript">
$(document).ready(function () {
var selectedTextBox;
$("input[type='text']").on("focusin", function () {
debugger;
selectedTextBox = this;
});
$("#ddlEmbedDBField").on("change", function () {
debugger;
var value = document.getElementById('<%=ddlEmbedDBField.ClientID%>').value;
if (document.getElementById('<%=ddlEmbedDBField.ClientID%>').value != "0")
{
$(selectedTextBox).val(value);
}
});
});
</script>
You could keep track of the selected text box whenever focus changes:
<script type="text/javascript">
$(document).ready(function(){
var selectedTextBox;
$("input[type='text']").on("focusin", function() {
selectedTextBox = this;
});
$('#ddl').on("change",function(){
var selectedVal = this.value;
$(selectedTextBox).val(selectedVal);
});
});
</script>
Obviously, if you have more than just the three textboxes you'd have to be more specific in your selector.
without using jQuery:
var lastclick;
function LastClicked(elem){
lastclick=elem;
}
function putText(area){
lastclick.value=area.value;
}
<input type="text" onblur="LastClicked(this)"/>
<input type="text" onblur="LastClicked(this)"/>
<input type="text" onblur="LastClicked(this)"/>
<input type="button" value="click me" onclick="putText(document.getElementById('mytext'))"/>
<textarea id="mytext" cols="20" rows="2"></textarea>
You keep track of the last element focused.
You can do it like
HTML Code
<input type='text' id='my-textbox1' />
<input type='text' id='my-textbox2' />
<input type='text' id='my-textbox3' /><br/>
<input type='button' id='btn' value='Click' />
JS Code
$(document).ready(function(){
var textSelected;
$("input[type='text']").on("focusout", function() {
textSelected = this;
});
$("#btn").on("click", function() {
$(textSelected).val("Hello");
});
});
Here is working Example
Click
check this code your purpose will be achieved. Hope it helps.
var inputFocusedId;
function loadValue(){
$('#'+inputFocusedId).val('abc');
}
function focussed(obj){
inputFocusedId = $(obj).attr('id');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="input1" onfocus="focussed(this);" />
<input type="text" id="input2" onfocus="focussed(this);" />
<input type="text" id="input3" onfocus="focussed(this);" />
<button onclick="loadValue()" >Submit</button>

Set cursor within text of input using jQuery

Using this topic:
jQuery Set Cursor Position in Text Area
I write this code but it does not works:
<input id="myTextInput" type="text" value="some text2">
<input type="button" value="set mouse" id="btn" />
and:
$(document).ready(function () {
$('#btn').on('click', function () {
var inp = $('#myTextInput');
var pos = 3;
inp.focus();
if (inp.setSelectionRange) {
inp.setSelectionRange(pos, pos);
} else if (inp.createTextRange) {
var range = inp.createTextRange();
range.collapse(true);
if (pos < 0) {
pos = $(this).val().length + pos;
}
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
});
});
DEMO
Where is my mistake?
Thanks
Your mistake is that you select the jQuery object instead of DOM element: replace var inp = $('#myTextInput'); with var inp = $('#myTextInput')[0];.
JSFIDDLE
However, I'd recommend using the plugin from this answer, since the code will look cleaner:
$.fn.selectRange = function(start, end) {
return this.each(function() {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
$(document).ready(function() {
$('#btn').on('click', function() {
var pos = 7;
$('#myTextInput').focus().selectRange(pos, pos);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="myTextInput" type="text" value="some text2">
<input type="button" value="set mouse" id="btn" />
You need DOM element rather than JQuery object to use setSelectionRange or createTextRange.
Use .get(0) to retreive it.
var inp = $('#myTextInput');
inp.focus();
inp = inp.get(0);
http://jsfiddle.net/qeanb8gk/1/

Behaviour Of Enter Key In Contenteditable Div

I'm trying to make a rich text editor and i have near to my success. I'm trying to change the behaviour of enter key in contenteditable div because when pressing enter firefox produced <br> thats ok but Chrome and IE produced a <p> and <div> here i'm trying to force all browser to produce <br> when press enter under <div contenteditable="true"></div>. Everything working fine in internet explorer but in all browsers would have to press enter two times for new line or <br>.
Here is my code.
<!doctype html>
<html>
<head>
<title>Rich Text Editor</title>
<script type="text/javascript">
function preview() {
var textbox = document.getElementById('textBox');
document.getElementById("view").innerHTML=textbox.innerHTML;
}
function enterKeyPressHandler(evt) {
var sel, range, br, addedBr = false;
evt = evt || window.event;
var charCode = evt.which || evt.keyCode;
if (charCode == 13) {
if (typeof window.getSelection != "undefined") {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
br = document.createElement("br");
range.insertNode(br);
range.setEndAfter(br);
range.setStartAfter(br);
sel.removeAllRanges();
sel.addRange(range);
addedBr = true;
}
} else if (typeof document.selection != "undefined") {
sel = document.selection;
if (sel.createRange) {
range = sel.createRange();
range.pasteHTML("<br>");
range.select();
addedBr = true;
}
}
// If successful, prevent the browser's default handling of the keypress
if (addedBr) {
if (typeof evt.preventDefault != "undefined") {
evt.preventDefault();
} else {
evt.returnValue = false;
}
}
}
}
function onload(){
var el = document.getElementById("textBox");
if (typeof el.addEventListener != "undefined")
{
el.addEventListener("keypress", enterKeyPressHandler , false);
}
else if (typeof el.attachEvent != "undefined")
{
el.attachEvent("onkeypress", enterKeyPressHandler);
}
}
</script>
</head>
<body onload="javascript:onload();">
<form name="myform" method="POST">
<div id="textBox" contenteditable="true" style="width:500px; height:150px; padding:20px; border:solid thin #000"></div>
</form>
<br>
<div id="view" style="width:500px; height:150px; padding:20px; border:solid thin #000"></div>
<br>
<button onClick="javascript:preview();">Preview</button>
</body>
</html
Demo JSFiddle
My solution is to handle an enter button. Different options for different tags. Look at https://codepen.io/MaratKh/pen/oKXxvV
const ed = document.getElementById('editable'),
ta = document.getElementById('txt');
const key13 = function(ev){
if(ev.keyCode==13) {
ev.preventDefault();
const selection = window.getSelection(),
range = selection.getRangeAt(0),
node = document.getSelection().anchorNode,
pNode = node.parentNode;
var tag = pNode.nodeName.toUpperCase();
switch(tag) {
case 'P':
tag = 'BR';
break;
case 'DIV':
tag = 'p';
break;
case 'SPAN':
tag = 'span';
break;
case 'BR':
tag = NULL;
break;
default:
tag = 'BR';
}
const el = document.createElement( tag );
range.deleteContents();
range.insertNode(el);
if ('BR'===tag) {
range.setStartAfter(el);
range.setEndAfter(el);
} else {
range.setStart(el, 0);
range.setEnd(el, 0);
}
const ze = document.createTextNode("\u200B");
range.insertNode(ze);
range.setStartBefore(ze);
range.setEndBefore(ze);
selection.removeAllRanges();
selection.addRange(range);
ev.stopPropagation();
}
ta.value = ed.innerHTML;
}
ed.addEventListener( 'keydown', key13, false);
.xrow {
display: block;
display: flex;
flex-direction: row;
align-items: stretch;
justify-content: space-between;
}
.xrow .col {
display: block;
flex: 1;
}
.xrow .col:first-child{
border-right:#669 1px dashed;
margin-right:20px;
}
textarea {
width:100%;
height:300px;
}
#editable{
padding:16px 9px;
border: 2px dashed #ddc;
}
<div class="xrow">
<div class="col">
<h3>Editable</h3>
<div id="editable" contenteditable="true">
<h1>Hi</h1>
<div>div</div>
<p>p</p>
text
</div>
</div>
<div class="col">
<h3>Result</h3>
<textarea id="txt"></textarea>
</div>
</div>
IT WORKS!!!
if (window.getSelection) {
var selection = window.getSelection(),
range = selection.getRangeAt(0),
br = document.createElement("br");
range.deleteContents();
range.insertNode(br);
var newLine=document.createTextNode('\n');
range.setStartAfter(br);
range.setEndAfter(br);
range.insertNode(newLine);
selection.removeAllRanges();
selection.addRange(range);
}

Categories

Resources