simple textarea string replace jquery script - javascript

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--;
..

Related

Javascript: Cannot move back in HTML Input

I have a form where a user can enter a URL but I wanted to have it automatically remove spaces.
To do this I have the following jQuery function:
$('#URL').on('change keyup', function() {
var sanitized = $(this).val().replace(' ', '');
$(this).val(sanitized);
});
But the problem with this code is that you cannot use the arrow keys to move in the input. i.e. if I type in http://oogle.com and I want to use arrow keys to fix my spelling mistake, it will automatically keep the cursor on the very last character. On top of this, I cannot use Ctrl+A to select all the text.
Is there a way to have jQuery/Javascript automatically remove spaces while still being able to move around the input or select it all?
Here is my jsFiddle showing my issue.
Use keypress instead of keyup, so only characters are caught. In this case, discard a space if it is pressed.
Also check for a paste event, and use a regular expression to replace all spaces. Change the value within a timeout in order to capture the pasted value:
$('#URL')
.on('keypress', function(e) {
if(e.which === 32) return false;
})
.on('paste', function() {
$self= $(this);
setTimeout(function() {
$self.val($self.val().replace(/\s/g, ''));
});
});
Fiddle
Fiddle
You can:
Record the cursor position
Execute your original code
Then restore the cursor position
Update:
Make sure to change your .replace to .replace(/\ /g, "")
Update 2 (cursor position):
This fixes the cursor position when inserting spaces.
For example copy and pasting the following will now work with any cursor position:
341 10365
34 1 1 03 65
First you need to get the string to the left of the cursor:
var leftString = $(this).val().substring(0, start);
Then you need to count the spaces in that string:
var leftSpaces = (leftString.match(/ /g) || []).length;
Then subtract leftSpaces from the start and end variables.
Javascript
$('#URL').on('change keyup', function() {
// Store cursor position
var start = this.selectionStart;
var end = this.selectionEnd;
// Check for newly inserted spaces
var leftString = $(this).val().substring(0, start);
var leftSpaces = (leftString.match(/ /g) || []).length;
newStart = start - leftSpaces;
newEnd = end - leftSpaces;
// Original Code
var sanitized = $(this).val().replace(/\ /g, "");
$(this).val(sanitized);
// Place cursor in correct position
this.setSelectionRange(newStart, newEnd);
});
Another option would be to add a delay after the keyup event
$('#URL').on('change keyup', function() {
delay(function(){
var sanitized = $('#URL').val().replace(' ', '');
$('#URL').val(sanitized);
}, 1000 );
});
http://jsfiddle.net/xv2e9bLe/
The usual way to adjust user input in a form is done when user finish their input or edit. It's pretty awkward to adjust user input on the fly. So, the onBlur event usually the best event to catch and sanitize a form input.
Based on the answer from adriancarriger, I use the 'blur' event which catch the user input after the user finish the input and do something else.
$('#URL').on('blur', function() {
var start = this.selectionStart,
end = this.selectionEnd;
var sanitized = $(this).val().replace(/\ /g, "");
$(this).val(sanitized);
this.setSelectionRange(start, end);
});
This should work well. If you have a real form submit, you can also catch the user input at onSubmit event of the form as well. Note that onSubmit happens at the form object, not the input object.

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

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

jQuery: scroll textarea to given position

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

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

Categories

Resources