jQuery: scroll textarea to given position - javascript

I have a textarea with lots and lots of text:
<textarea cols="50" rows="10" id="txt">lots and lots of text goes here</textarea>
I want to scroll the textarea down, so the user can see 2000-th character. How can I do this using javasctipt/jQuery?
$('#txt').scrollToCharNo(2000); // something like this would be great
EDIT (my solution)
Well, I managed to make it work myself. The only way I found, is to create a DIV with the same font and width as the textarea, put a SPAN near the needed character and find the position of that span.
I am sure, that somebody might find my solution useful, so i'll paste it here:
jQuery.fn.scrollToText = function(search) {
// getting given textarea contents
var text = $(this).text();
// number of charecter we want to show
var charNo = text.indexOf(search);
// this SPAN will allow up to determine given charecter position
var anch = '<span id="anch"></span>';
// inserting it after the character into the text
text = text.substring(0, charNo) + anch + text.substring(charNo);
// creating a DIV that is an exact copy of textarea
var copyDiv = $('<div></div>')
.append(text.replace(/\n/g, '<br />')) // making newlines look the same
.css('width', $(this).attr('clientWidth')) // width without scrollbar
.css('font-size', $(this).css('font-size'))
.css('font-family', $(this).css('font-family'))
.css('padding', $(this).css('padding'));
// inserting new div after textarea - this is needed beacuse .position() wont work on invisible elements
copyDiv.insertAfter($(this));
// what is the position on SPAN relative to parent DIV?
var pos = copyDiv.find('SPAN#anch').offset().top - copyDiv.find('SPAN#anch').closest('DIV').offset().top;
// the text we are interested in should be at the middle of textearea when scrolling is done
pos = pos - Math.round($(this).attr('clientHeight') / 2);
// now, we know where to scroll!
$(this).scrollTop(pos);
// no need for DIV anymore
copyDiv.remove();
};
$(function (){
$('#scroll_button').click(
function() {
// scrolling to "FIND ME" using function written above
$('#txt').scrollToText('FIND ME');
return false;
}
);
});
Here is a demo (it works!): http://jsfiddle.net/KrVJP/
Since none of the answers actually solved the problem, I'll accept experimentX's one: thank you for putting an effort to help me, I appreciate it!

I am not sure if it will work. Please also check it here. It's seems working for 2000th, 1500th, and 1000th position.
EDIT confused font-size or line-height ???
$(function (){
var height = 2000/$('#txt').attr('cols');
$('#txt').scrollTop(height*13);
$('#txt').selectRange(2000,2000); //this is just to check
});
$.fn.selectRange = function(start, end) { //this is just to check
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();
}
});
};
UPDATE How about this one
var height = 1200/$('#txt').attr('cols');
var line_ht = $('#txt').css('line-height');
line_ht = line_ht.replace('px','');
height = height*line_ht;

You can use this jquery plugin

Related

How to change the caret offset in a rich text editor textarea?

I have a wysihtml rich text editor. If certain conditions are met I want to change the offset of the caret.
Because a wysithtml textarea is not really a textarea div (it's just a regular div) I can't use the common textarea strategies to move the caret. But after some experimentation I found out that treating it as a Selection enables me to work with it as a textarea.
From what I read the correct method to change the caret offset is Range.setStart(), but I can't figure out how to use it. Anyone who can help me?
I have set up this jsfiddle. Try (in Firefox) to move the caret to offset 27. Then the value of the editor will change, and the caret will move to offset 0. But how do I move the caret to e.g. offset 35?
I have updated your fiddle to work like you want.
This is the part i modified :
if (offsets.start_offset == 27) {
editor.setValue("This is first line.<br>This is another second line.", true);
/* START OF MODIFICATION */
var range = window.getSelection().getRangeAt(0);
range.selectNodeContents(textarea);
var fromPos = 27;
var lenTotal = ( textarea.textContent || textarea.innerText ).length;
var lenCurTextNode = range.endContainer.lastChild.nodeValue.length;
var lenNewWord= 'another '.length ;
var newPos = ( fromPos - (lenTotal - lenCurTextNode) ) + lenNewWord;
range.setStart(range.startContainer.lastChild , newPos);
range.setEnd(range.endContainer.lastChild , newPos);
/* END OF MODIFICATION */
var offsets = getOffsets(textarea);
console.log("I want offsets.start_offset to be 35, but it is " + offsets.start_offset)
} else {
console.log("Offset is from " + offsets.start_offset + " to " + offsets.end_offset );
}
You have to deal with the textNode to create a range of text characters and not whith the HTMLElement.
It was for that, your Range.setStart(), had no effect, it was 'ranging' divs !
In your sample textarea is a div in which you need to find each textNode and interact with them.
In the code above range.endContainer.lastChild is a textNode (in reality the lastChild of textarea).
Hope this will help you !
Tested with Firefox

simple textarea string replace jquery script

I'm trying to make some simple jquery script that replaces a specific string in the textarea. I've got this know:
$("textarea").bind("keyup", function() {
var text = $(this).val();
text = text.replace(/,,/g, "′");
$(this).val(text);
});
This replaces ,, into the unicode symbol ′. This works, except that the cursors position moves to the last character of the textarea everytime there is a replacement. I want that the cursors goes just after the ′ when there is a replacement. How could I do this ?
Here is my jsfiddle: http://jsfiddle.net/zvhyh/
Edit: thanks for the help guys. I use this now:
http://jsfiddle.net/zvhyh/14/
Here is my take on it:
http://jsfiddle.net/zvhyh/11/
$("textarea").bind("keyup", function() {
var cursorPosition = $('textarea').prop("selectionStart");
var text = $(this).val();
if (text.indexOf(',,') > -1) {
text = text.replace(/,,/g, "′");
$(this).val(text);
$('textarea').prop("selectionStart", cursorPosition - 1);
$('textarea').prop("selectionEnd", cursorPosition - 1);
}
});
Here is your updated fiddle: http://jsfiddle.net/zvhyh/10/
The key is to use selectionStart to get the current position of cursor and setSelectionRange to place the cursor in that position later on.
// get current cursor position
var pos = $(this).val().slice(0, this.selectionStart).length;
// replace the text
$(this).val($(this).val().replace(/,,/g, "′"));
// reset the cursor position
this.setSelectionRange(pos, pos);
Hope that helps.
Update:
Because two characters are being replaced by one character, in the above code the cursor position will skip one character to right. One workaround is to first check if a ",," combo is there, and then use the position as one character before.
Updated fiddle: http://jsfiddle.net/zvhyh/13/
if (text.indexOf(",,") > 0) {
...
pos--;
..

Insert value into TEXTAREA where cursor was

I have a textarea and a div with values. When I click on a value I insert it into textarea. I need it to be inserted where my cursor was in textarea. Why do I say WAS? Because when I move it out and click on a value to insert, I assume it looses focus in the text area.
So, my question is, is there a way to "remember" the latest cursor position within textarea and then insert my values at that position?
Perhaps it could be a char number in a string?.. Currently I add it like this:
input.val( function( i, val ) { return val + " " + myInsert + " "; } );
Also I use jQuery, perhaps I could use it?
I've written a cross-browser jQuery plug-in for dealing with the caret/selection in textareas and text inputs called Rangy inputs (terrible name, I really should think of a better one). A combination of methods from this and the techniques in Edgar Villegas Alvarado's answer should do the trick, although in IE, the focusout event fires too late and you'll need to use the proprietary beforedeactivate event instead:
var $textBox = $("#foo");
function saveSelection(){
$textBox.data("lastSelection", $textBox.getSelection());
}
$textBox.focusout(saveSelection);
$textBox.bind("beforedeactivate", function() {
saveSelection();
$textBox.unbind("focusout");
});
When inserting text later, the following will insert text at the previous cursor position (or overwrite the previously selected text, if the user had selected any):
var selection = $textBox.data("lastSelection");
$textBox.focus();
$textBox.setSelection(selection.start, selection.end);
$textBox.replaceSelectedText("Some new text");
See jsFiddle example here: http://jsfiddle.net/rQXrJ/1/
Here is a working example of what you are trying to do check it out at:
http://jsfiddle.net/J5Z2n/1/
Hello there my good friend....
how do you do
the jQuery:
function insertAt (myField, myValue, startSel, endSel) {
if (startSel || startSel == '0') {
var startPos = startSel;
var endPos = endSel;
myField.val(myField.val().substring(0, startPos)+ myValue+ myField.val().substring(endPos, myField.val().length));
}
else {
myField.val() += myValue;
}
}
// calling the function
var targetBox = $('textarea#insert'),
startSel,
endSel;
targetBox.bind('focusout', function() {
//insertAtCursor(this, 'how do you do');
startSel = this.selectionStart;
endSel = this.selectionEnd;
});
$("#myvalue").click(function() {
var myValue = $(this).text();
insertAt(targetBox, myValue, startSel, endSel);
});
The original function was borrowed from this post
http://alexking.org/blog/2003/06/02/inserting-at-the-cursor-using-javascript
That should give you a solid head start I hope. Cheers
If the caret (the cursor) is somewhere in the text field, it registers in Javascript as an empty selection. That is, the selectionStart and selectionEnd attributes are the same. You can use those attributes to detect the position of the caret.
Apparently selectionStart and selectionEnd are quite useful here. Check this out:
http://www.scottklarr.com/topic/425/how-to-insert-text-into-a-textarea-where-the-cursor-is/
You can use the jQuery Caret plugin to get/set the cursor position .
Example usage:
var cursorPosition = $("#textbox").caret().start);
You could 'store' this position like this:
$("#textbox").focusout(function(){
var cursorPosition = $(this).caret().start);
$(this).data("lastCursorPos", cursorPosition);
});
To retrieve it (on your div click event), do this:
var lastCursorPosition = $("#textbox").data("lastCursorPos");
Hope this helps. Cheers

Keypress in jQuery: Press TAB inside TEXTAREA (when editing an existing text)

I want to insert TAB characters inside a TEXTAREA, like this:
<textarea>{KEYPRESS-INSERTS-TAB-HERE}Hello World</textarea>
I can insert before/after the existing TEXTAREA text - and I can insert / replace all text in the TEXTAREA - but have not yet been able to insert inside the existing TEXTAREA text (by the cursor) in a simple way.
$('textarea:input').live('keypress', function(e) {
if (e.keyCode == 9) {
e.preventDefault();
// Press TAB to append a string (keeps the original TEXTAREA text).
$(this).append("TAB TAB TAB AFTER TEXTAREA TEXT");
// Press TAB to append a string (keeps the original TEXTAREA text).
$(this).focus().prepend("TAB TAB TAB BEFORE TEXTAREA TEXT");
// Press TAB to replace a all text inside TEXTAREA.
$(this).val("INSERT INTO TEXTAREA / REPLACE EXISTING TEXT");
}
});
There is a "tabs in textarea" plug-in for jQuery ("Tabby") - but it's 254 code lines - I was hoping for just a few lines of code.
A few links that I studied: (again, I would prefer fewer code lines).
http://www.dynamicdrive.com/forums/showthread.php?t=34452
http://www.webdeveloper.com/forum/showthread.php?t=32317
http://pallieter.org/Projects/insertTab/
Please advise. Thanks.
I was creating a AJAX powered simple IDE for myself so I can rapidly test out PHP snippets.
I remember stumbling upon the same problem, here's how I solved it:
$('#input').keypress(function (e) {
if (e.keyCode == 9) {
var myValue = "\t";
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
e.preventDefault();
}
});
#input is the ID of the textarea.
The code is not completely mine, I found it on Google somewhere.
I've only tested it on FF 3.5 and IE7. It does not work on IE7 sadly.
Unfortunately, manipulating the text inside textarea elements is not as simple as one might hope. The reason that Tabby is larger than those simple snippets is that it works better. It has better cross-browser compatibility and handles things like tabbing selections.
When minified, it's only about 5k. I'd suggest using it. You'll either have to discover and troubleshoot those same edge cases yourself anyway, or might not even know about them if users don't report them.
Yeah, dealing with input field selections across the different browsers is an annoyance, especially as in IE there are a few methods that look like they should work but actually don't. (Notably, combining using setEndPoint then measuring length, which looks OK until the selection starts or ends in newlines.)
Here's a couple of utility functions I use to deal with input selections. It returns the value of the input split into bits that are before, inside and after the selection (with the selection counting as an empty string at the input focus position if it's not a selection). This makes it fairly simply to replace and insert content at the point you want, whilst taking care of the IE CRLF problem.
(There may be a jQuery that does something like this, but I have yet to meet one.)
// getPartitionedValue: for an input/textarea, return the value text, split into
// an array of [before-selection, selection, after-selection] strings.
//
function getPartitionedValue(input) {
var value= input.value;
var start= input.value.length;
var end= start;
if (input.selectionStart!==undefined) {
start= input.selectionStart;
end= input.selectionEnd;
} else if (document.selection!==undefined) {
value= value.split('\r').join('');
start=end= value.length;
var range= document.selection.createRange();
if (range.parentElement()===input) {
var start= -range.moveStart('character', -10000000);
var end= -range.moveEnd('character', -10000000);
range.moveToElementText(input);
var error= -range.moveStart('character', -10000000);
start-= error;
end-= error;
}
}
return [
value.substring(0, start),
value.substring(start, end),
value.substring(end)
];
}
// setPartitionedValue: set the value text and selected region in an input/
// textarea.
//
function setPartitionedValue(input, value) {
var oldtop= input.scrollTop!==undefined? input.scrollTop : null;
input.value= value.join('');
input.focus();
var start= value[0].length;
var end= value[0].length+value[1].length;
if (input.selectionStart!==undefined) {
input.selectionStart= start;
input.selectionEnd= end;
if (oldtop!==null)
input.scrollTop= oldtop;
}
else if (document.selection!==undefined) {
var range= input.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
}
btw, see also:
http://aspalliance.com/346_Tabbing_in_the_TextArea

How do I insert a character at the caret with javascript?

I want to insert some special characters at the caret inside textboxes using javascript on a button. How can this be done?
The script needs to find the active textbox and insert the character at the caret in that textbox. The script also needs to work in IE and Firefox.
EDIT: It is also ok to insert the character "last" in the previously active textbox.
I think Jason Cohen is incorrect. The caret position is preserved when focus is lost.
[Edit: Added code for FireFox that I didn't have originally.]
[Edit: Added code to determine the most recent active text box.]
First, you can use each text box's onBlur event to set a variable to "this" so you always know the most recent active text box.
Then, there's an IE way to get the cursor position that also works in Opera, and an easier way in Firefox.
In IE the basic concept is to use the document.selection object and put some text into the selection. Then, using indexOf, you can get the position of the text you added.
In FireFox, there's a method called selectionStart that will give you the cursor position.
Once you have the cursor position, you overwrite the whole text.value with
text before the cursor position + the text you want to insert + the text after the cursor position
Here is an example with separate links for IE and FireFox. You can use you favorite browser detection method to figure out which code to run.
<html><head></head><body>
<script language="JavaScript">
<!--
var lasttext;
function doinsert_ie() {
var oldtext = lasttext.value;
var marker = "##MARKER##";
lasttext.focus();
var sel = document.selection.createRange();
sel.text = marker;
var tmptext = lasttext.value;
var curpos = tmptext.indexOf(marker);
pretext = oldtext.substring(0,curpos);
posttest = oldtext.substring(curpos,oldtext.length);
lasttext.value = pretext + "|" + posttest;
}
function doinsert_ff() {
var oldtext = lasttext.value;
var curpos = lasttext.selectionStart;
pretext = oldtext.substring(0,curpos);
posttest = oldtext.substring(curpos,oldtext.length);
lasttext.value = pretext + "|" + posttest;
}
-->
</script>
<form name="testform">
<input type="text" name="testtext1" onBlur="lasttext=this;">
<input type="text" name="testtext2" onBlur="lasttext=this;">
<input type="text" name="testtext3" onBlur="lasttext=this;">
</form>
Insert IE
<br>
Insert FF
</body></html>
This will also work with textareas. I don't know how to reposition the cursor so it stays at the insertion point.
In light of your update:
var inputs = document.getElementsByTagName('input');
var lastTextBox = null;
for(var i = 0; i < inputs.length; i++)
{
if(inputs[i].getAttribute('type') == 'text')
{
inputs[i].onfocus = function() {
lastTextBox = this;
}
}
}
var button = document.getElementById("YOURBUTTONID");
button.onclick = function() {
lastTextBox.value += 'PUTYOURTEXTHERE';
}
Note that if the user pushes a button, focus on the textbox will be lost and there will be no caret position!
loop over all you input fields...
finding the one that has focus..
then once you have your text area...
you should be able to do something like...
myTextArea.value = 'text to insert in the text area goes here';
I'm not sure if you can capture the caret position, but if you can, you can avoid Jason Cohen's concern by capturing the location (in relation to the string) using the text box's onblur event.
A butchered version of #bmb code in previous answer works well to reposition the cursor at end of inserted characters too:
var lasttext;
function doinsert_ie() {
var ttInsert = "bla";
lasttext.focus();
var sel = document.selection.createRange();
sel.text = ttInsert;
sel.select();
}
function doinsert_ff() {
var oldtext = lasttext.value;
var curposS = lasttext.selectionStart;
var curposF = lasttext.selectionEnd;
pretext = oldtext.substring(0,curposS);
posttest = oldtext.substring(curposF,oldtext.length);
var ttInsert='bla';
lasttext.value = pretext + ttInsert + posttest;
lasttext.selectionStart=curposS+ttInsert.length;
lasttext.selectionEnd=curposS+ttInsert.length;
}

Categories

Resources