Find carret position x y inside textarea with javascript - javascript

What Im trying to do is - i dont know the name maybe - a Prediction Help Inputter inside a textarea. It uses jquery autocomplete. When the user types '[[g ' inside textarea (id=test), a input with autocomplete is opened (id=example), so it search in 'data'. When the user find the desired data, he must press Shif+Enter to insert the data into the textarea, closing with ']]'.
How could I find the position of the carret to make the input appears near there?
I dont want to find the index of the carret, but something like the x y absolute position.
What do you suggest me?
Code above:
<textarea onkeydown="predicao(this);" cols="40" rows="10" id="test" onfocus="this.focus()"></textarea>
<input id="example" style="display: none;" onkeyup="insert(this, event);"/>
<script language="Javascript">
<!--
function predicao(objeto){
comprimento = objeto.value.length;
var antipenultimo = comprimento - 4;
var input = objeto.value.substring(antipenultimo,comprimento);
var output = "";
for(i=0; i<input.length; ++i){
if(output != "") output += ", ";
output += input.charCodeAt(i);
}
if (output == "91, 91, 103, 32"){
var preditor = document.getElementById('example');
preditor.value = '';
preditor.style.display = 'block';
preditor.focus();
preditor.select();
}
}
function insert(objeto, evt){
var e = evt || event;
var code = e.keyCode || e.which;
if(e.shiftKey && code == '13') {
var texto = document.getElementById('test').value;
texto += objeto.value+']]';
document.getElementById('test').focus();
document.getElementById('test').value = texto;
objeto.style.display = 'none';
}
}
$(document).ready(function(){
var data = "Afrikaans Català Deutsch English Esperanto Suomi Français Galego Hrvatski Magyar Bahasa Indonesia Italiano Basa Jawa".split(" ");
$("#example").autocomplete(data);});
</script>

Something like:
var pos = $('textarea').caret(); // using caret plugin...
var lines = $('textarea').val().slice(0, pos).replace(/\t/g, ' ').split('\n');
var y = lines.length;
var x = lines[y-1].length;
Should work reasonably well for fix-width fonts.

If you're looking to do it via JS only:
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);
}
Courtesy: http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/
Demo: http://demo.vishalon.net/getset.htm

Related

How to only show few characters when pasting text in editor?

trying to paste characters and if it is more than 50 characters ONLY show the first 50 characters. Can anyone tell me what I'm missing?
Here's my code: LIVE DEMO
CKEDITOR.instances.foo.on('paste',function(event){
alert('paste');
var deleteKey = 46;
var backspaceKey = 8;
var keyCode = event.data.keyCode;
if (keyCode === deleteKey || keyCode === backspaceKey)
return true;
else
{
var textLimit = 50;
var str = CKEDITOR.instances.foo.getData();
if (str.length >= textLimit)
// Need to add code here to only show the first 50 characters
return false;
}
});
You can use the WORDCOUNT plugin of CKEditor and you can find the example
https://ckeditor.com/cke4/addon/wordcount
You can use this event.data.dataValue to get and set data from CKEditor
CKEDITOR.instances.foo.on('paste',function(event){
var textLimit = 50;
var str = $(event.data.dataValue).text();
if (str.length >= textLimit) {
event.data.dataValue = str.substr(0 , textLimit);
}
});
http://jsfiddle.net/2ftroyuv/7/
the document show about paste event.
https://docs.ckeditor.com/ckeditor4/latest/guide/dev_clipboard.html#the-paste-event
you could use event.data.dataValue to get the paste content.
code is here:
http://jsfiddle.net/2vzkLb8L/2/
CKEDITOR.instances.foo.on('paste',function(event){
var pasteContent = event.data.dataValue;
var str = CKEDITOR.instances.foo.getData();
var textLimit = 50;
var newcontent = pasteContent + str;
CKEDITOR.instances.foo.setData(newcontent.slice(0,50))
});

Insert several elements inside an editable div at cursor position

I have a div with the contenteditable attribute. The user needs to be able to type and insert several select menus where the cursor is. I've managed to get the cursor position and to insert the first select menu, but it only works on the first text node.
That's how I get the cursor position:
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;
}
Then I update it every time the user types or clicks.
function updatePos() {
var el = document.getElementById("msg");
pos = getCaretCharacterOffsetWithin(el);
}
document.body.onkeyup = updatePos;
document.body.onmouseup = updatePos;
Then here's how I'm handling the button that adds the select. I'm not sure how to insert an element after a text node, so I insert a br tag and remove it later. There has to be a cleaner way, right?
$('#btn').click(function(){
var selectList = document.createElement('select');
var msg = $('#msg');
$(msg).html(function(){
var first = $(msg).html().substring(0, pos);
var last = $(msg).html().substring(pos);
return first + '<br>' + last;
});
$(msg).contents().filter('br').after(selectList);
$(msg).contents().filter('br').remove();
$(msg).focus();
})
I guess the problem is that I'm using substring to split the text and be able to insert the select there, and as soon as there is another select tag, the substring is not able to go past the first text node. So maybe I'm supposed to redo the whole thing with a different approach, but I'm completely stuck.
Here's the jsfiddle: https://jsfiddle.net/8a63sosr/
Thanks!
The problem is that for HTML elements it takes, well, in terms of jQuery, text(), not html().
I guess there's a better solution with some range parameters, but here's something:
//fix caret pos
var temlOffset = pos;
$('#msg').html().split(/(<[^>]+>)/g).forEach(function(el){
if(temlOffset > 0){
if(el.length && el[0] === '<'){
pos += el.length;
} else {
temlOffset -= el.length;
}
}
});
https://jsfiddle.net/Lemz17L8/
So, what it does is adding the html tag length to the pos value.
Best regards, Alexander

How to get cursor position in rich:editor richfaces by javascript

I have a rich:editor
<rich:editor id="editor" width="1000" height="300"
value="#{emailTemplateHome.instance.emailTemplateContent}"
theme="advanced">
</rich:editor>
and javascript function
function change(){
var val = document.getElementById("#{rich:clientId('editor')}");
if(val != null){
var component = val.component;
var content = component.tinyMCE_editor.getContent();
var position = content.slice(0, val.positionedOffset).length;
var result = content.substr(0,position) + "{chuc_vu}" + content.substr(position);
component.tinyMCE_editor.setContent(result);
}
}
but var position is not defined.
How can i get position of current cursor ???
Thanks in advance
If you only want to insert things at the current position you can use this:
component.tinyMCE_editor.execCommand('mceInsertContent', false, "insert text");
If you want to do something with the cursor position that's going to be tricky, since the position in the editor doesn't correspond to the position in the content (the content has HTML tags in it). You can get the position this way:
component.tinyMCE_editor.selection.getBookmark().start
val.positionedOffset is a function that returns an array, I'm not sure what you were using that for (not to mention that slice(0,x).length = x)
Writing something after cursor position:
function writeAfterCursor(element) {
var bm =tinyMCE.activeEditor.selection.getBookmark().start;
var content= tinyMCE.activeEditor
.getContent();
content= strip(content);
var res = content.split("");
var res1= [];
var res2= [];
for(i=0; i < bm; i++){
res1[i]=res[i];
}
var j=0;
for(i=bm; i < res.length; i++){
res2[j]=res[i];
j++;
}
var content1= res1.join("");
var content2= res2.join("");
content = content1+ element.value+content2;
tinyMCE.activeEditor.setContent(content);
tinyMCE.activeEditor.selection.moveToBookmark(bm);
}
function strip(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}

Firefox triple click selection returns incorrect start and end offsets

I have this piece of code which is supposed to return the start and end offsets of the user selection:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
alert(range.startOffset+"-"+range.endOffset);
}
</script>
</head>
<body>
<button onclick="getSelRange()">Get the selected text!</button>
<p>Select some text!</p>
</body>
</html>
When I select some text from the p by dragging, it alerts the numbers correctly. However, when I select the entire text in the p by triple clicking on it, it alerts 0-1. Looks like in Firefox only, triple click doesn't return the selection range correctly.
How do I get the correct start and end points on triple click as well?
Firefox is returning the correct range. The problem is that your assumption that a range must have its start and end boundaries relative to a text node is incorrect.
What is happening is that Firefox is reporting the range as starting before the zeroth child node of the <p> element and ending after the first child of the <p> element. This is perfectly valid.
You could do something like the following to adjust such a range to make its boundaries lie inside the text node within the <p> element:
Demo: http://jsfiddle.net/DbmjH/2/
Code:
function adjustRange(range) {
range = range.cloneRange();
if (range.startContainer.nodeType != 3) {
var nodeAfterStart = range.startContainer.childNodes[range.startOffset];
if (nodeAfterStart && nodeAfterStart.nodeType == 3) {
range.setStart(nodeAfterStart, 0);
}
}
if (range.endContainer.nodeType != 3 && range.endOffset >= 1) {
var nodeBeforeEnd = range.endContainer.childNodes[range.endOffset - 1];
if (nodeBeforeEnd && nodeBeforeEnd.nodeType == 3) {
range.setEnd(nodeBeforeEnd, nodeBeforeEnd.data.length);
}
}
return range;
}
Check this fiddle ( Updated )
I have made it in a way that it will work on triple click when paragraph contains multiple lines.
<script>
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
var r = document.getElementById('txt').innerHTML.split('<br>');
if (r[(range.endOffset-1)/2] == selObj) {
alert(0+"-"+r[(range.endOffset-1)/2].length);
} else if (range.startOffset >= range.endOffset) {
alert(range.startOffset + "-" + r[(range.endOffset-1)/2].length);
} else {
alert(range.startOffset + "-" + range.endOffset);
}
}
</script>
New Added Fiddle
<script>
function getSelRange() {
var selObj = window.getSelection();
var range = selObj.getRangeAt(0);
var r=document.getElementById('txt').innerHTML.split('<br>');
var selLines = selObj.toString().split('\n');
var Str = document.getElementById('txt').innerHTML;
Str=Str.replace(/<br>/g,"xzznlzzx");
var pr=selObj.toString().replace(/\r?\n/g,"xzznlzzx");
var rStr=Str.substring(0,Str.indexOf(pr));
var rSplit=rStr.split('xzznlzzx');
var prSplit=pr.split('xzznlzzx');
var countStart=0;
var countEnd=0;
var i=0;
for(;i<(rSplit.length-1);i++)
{
countStart=countStart+r[i].length;
}
for(j=0;j<(prSplit.length-1);i++,j++)
{
countEnd=countEnd+r[i].length;
}
countEnd=countEnd+countStart;
if(r[(range.endOffset-1)/2]==selObj)
{
alert((0+countStart)+"-"+(r[(range.endOffset-1)/2].length+countEnd));
}
else{
if(r[i].length<selObj.toString().length)
{
var indx = selObj.toString().indexOf(r[i]);
}
else{
var indx = r[i].indexOf(selObj.toString());
var vals=selObj.toString().length;
var res = r[i].substring(indx+vals,indx+vals+1);
if(res==""){indx=1}
else{indx=-1}
}
if(indx!=-1)
{
alert((range.startOffset+countStart)+"-"+(r[i].length+countEnd));
}
else{
alert((range.startOffset+countStart)+"-"+(range.endOffset+countEnd));
}
}
}
</script>
Note : for the above fiddles to work the string within <p> tag must be in a single line otherwise it will add the extra spaces between words to the range.

How to transpose two characters in a textarea

How can I get at the content of a text area and swap the two characters around the cursor, in Javascript? I want to write a tiny, but useful Chrome extension that will let me do this when I mistype in gmail. (I'm assuming that the the main editing area in gmail is a textarea).
This may be a question too stupid to ask here. In any case, I have searched for an answer and failed. I'm not a real programmer, but I have written snippets to do this in other scripting languages. It's easy enough to do it Firefox, for example, with an autohotkey script. For some reason the Javascript quite defeats me.
See the code in http://jsfiddle.net/Lg3Ng/
HTML:
<textarea id="my_text" onclick="changeChar();"></textarea>
JAVASCRIPT:
function changeChar() {
var pos = getCaretPosition(document.getElementById("my_text"));
//alert(pos);
if (pos > 0) swapChars(pos - 1);
}
function swapChars(pos) {
var cur_val = document.getElementById("my_text").value;
var firstChar = cur_val.charAt(pos);
var secondChar = cur_val.charAt(pos + 1);
var startString = cur_val.substr(0, pos);
var endString = cur_val.substring(pos + 2);
document.getElementById("my_text").value = startString + secondChar + firstChar + endString;
}
// From http://demo.vishalon.net/getset.htm
function getCaretPosition(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);
}

Categories

Resources