Is There an Internet Explorer Approved Substitute for Selectionstart and Selectionend

Is there an Internet Explorer approved substitute for selectionStart and selectionEnd?

I'll post this function for another time, seeing as this question got linked to from another one.

The following will do the job in all browsers and deals with all new line problems without seriously compromising performance. I've arrived at this after some toing and froing and now I'm pretty convinced it's the best such function around.

UPDATE

This function does assume the textarea/input has focus, so you may need to call the textarea's focus() method before calling it.

function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;

if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();

if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");

// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());

// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);

if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;

if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}

return {
start: start,
end: end
};
}

var el = document.getElementById("your_input");
el.focus();
var sel = getInputSelection(el);
alert(sel.start + ", " + sel.end);

selection range in IE

Found the solution here, its a huge code block so I don't want to post the answer here.

How to replace selected text in a textarea with Javascript?

For non IE browsers you can do something like this using selectionStart and SelectionEnd properties of textarea object:

function createListElement() {
if(document.activeElement === textarea) {
if(typeof textarea.selectionStart == 'number' && typeof textarea.selectionEnd == 'number') {
// All browsers except IE
var start = textarea.selectionStart;
var end = textarea.selectionEnd;

var selectedText = textarea.value.slice(start, end);
var before = textarea.value.slice(0, start);
var after = textarea.value.slice(end);

var text = before + '- ' + selectedText + after;
textarea.value = text;
}
}
}

But such a trivial manipulation is getting much harder for IE, you can find more here.

I hope this will help you :)

Character offset in an Internet Explorer TextRange

I'd suggest IERange, or just the TextRange-to-DOM Range algorithm from it.

Update, 9 August 2011

I'd now suggest using my own Rangy library, which is similar in idea to IERange but much more fully realized and supported.

Is there a way to get the offset of the selected text within an input box in IE?

A direct quote from a previous response to a very similar question that will get you a selection range:

function getSelection(inputBox) {
if ("selectionStart" in inputBox) {
return {
start: inputBox.selectionStart,
end: inputBox.selectionEnd
}
}

//and now, the blinkered IE way
var bookmark = document.selection.createRange().getBookmark()
var selection = inputBox.createTextRange()
selection.moveToBookmark(bookmark)

var before = inputBox.createTextRange()
before.collapse(true)
before.setEndPoint("EndToStart", selection)

var beforeLength = before.text.length
var selLength = selection.text.length

return {
start: beforeLength,
end: beforeLength + selLength
}
}

IE's document.selection.createRange doesn't include leading or trailing blank lines

I'm adding another answer since my previous one is already getting somewhat epic.

This is what I consider the best version yet: it takes bobince's approach (mentioned in the comments to my first answer) and fixes the two things I didn't like about it, which were first that it relies on TextRanges that stray outside the textarea (thus harming performance), and second the dirtiness of having to pick a giant number for the number of characters to move the range boundary.

function getSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;

if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();

if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");

// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());

// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);

if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;

if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}

return {
start: start,
end: end
};
}

var el = document.getElementById("your_textarea");
var sel = getSelection(el);
alert(sel.start + ", " + sel.end);

Replace text in textarea using Javascript

textareaClicked = function(e){
var pos = e.target.selectionStart;
var beforeSelection = e.target.innerHTML.slice(0,pos);
var afterSelection = e.target.innerHTML.slice(pos);
var newHTML = beforeSelection.replace(/\d/g,4) + afterSelection;
e.target.innerHTML = newHTML;
e.target.setSelectionRange(pos,pos);
};

document.getElementById('foo').onclick=textareaClicked;

see it in action in this jsfiddle.

Replacing text inside textarea without focus

So, you want to persist the selection when you focus out of the textarea and focus on the input tag.

You need to remember the selection (start and end points when the text area loses focus) and force the selection so that it persists.

To remember the selection, you can store the el.selectionStart and el.selectionEnd in two global variables inside a function which is called at onblur() event of textarea tag.

Then inside your pasteIntoInput() you can consider those two points for replacement.

To force selection - Check this solution for persisting the selection. This uses jquery however, not plain javascript.

However, I am not sure whether the solution actually works. I tried it here http://jsfiddle.net/sandeepan_nits/qpZdJ/1/ but it does not work as expected.

Updates

I doubt if it is possible to persist selection after focus is gone. Probably selection needs focus to be there and the answer link that I gave tries to focus and then select. In that case this will not solve your problem. So, the alternatives could be -

  • faking a text area with an html div. You can define some styles to create a selection like effect and apply it onblur() or use a simple readymade editor if available.

  • Displaying the selection dynamically in a separate area. Check this demo of jquery fieldSelection plugin . Remember that you are already storing the selection in global variables for the actual replacement. You only need to display to the user the selection which will be replaced. I think displaying the selection separately like this demo saves your time and it looks cool too.

But depends on your requirement of course.

Further Update

Check http://jsfiddle.net/sandeepan_nits/qpZdJ/2/ for a working "Replacing text inside textarea without focus" (like you want) but without the selection on blur. I still don't know whether it is possible to keep the selection on blur.

Another Update (21st December)

Working solution for IEs as well as other browsers
http://jsfiddle.net/sandeepan_nits/qpZdJ/24/

Here is the same code:-

The html -

<textarea id='text' cols="40" rows="20" onbeforedeactivate="storeSelectionIeCase();" onblur="storeSelectionOthersCase();">
</textarea>

<div id="opt">
<input id="input" type="text" size="35">
<input type="button" onclick='pasteIntoInput(document.getElementById("input").value)' value="button"/>

</div>

and all the js

var storedSelectionStart = null;
var storedSelectionEnd = null;

function pasteIntoInput(text)
{

el=document.getElementById("text");

el.focus();
if((storedSelectionStart != null) && (storedSelectionEnd != null))
{
start = storedSelectionStart;
end = storedSelectionEnd;
}
else
{
start = el.selectionStart;
end = el.selectionEnd;
}
if (typeof start == "number"&& typeof end == "number")
{
var val = el.value;
var selStart = start;
var end = selStart + text.length;
el.value = val.slice(0, selStart) + text + val.slice(end );
}
else if (typeof document.selection != "undefined")
{
var textRange = document.selection.createRange();
textRange.text = text;
textRange.collapse(false);
textRange.select();
}
}

function storeSelectionOthersCase()
{
if(!(isBrowserIE6() || isBrowserIE7()))
{
storeSelection();
}
else
{
return false;
}
}

function storeSelectionIeCase()
{
if((isBrowserIE6() || isBrowserIE7()))
{
storeSelection();
}
else
{
return false;
}
}

function storeSelection()
{
//get selection
el=document.getElementById("text");

var el = document.getElementById("text");
var sel = getInputSelection(el);
//alert("check"+sel.start + ", " + sel.end);

storedSelectionStart = sel.start;
storedSelectionEnd = sel.end;

//alert("see"+storedSelectionStart +" - "+storedSelectionEnd );
}

function getInputSelection(el)
{
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;

if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();

if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");

// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());

// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);

if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;

if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}

return {
start: start,
end: end
};
}

function isBrowserIE6()
{
var ret = false;
if(($.browser.msie) && (parseInt($.browser.version) == 6) && (!this.XMLHttpRequest))
{
ret = true;
}
return ret;
}

function isBrowserIE7()
{
var ret = false;
if(($.browser.msie) && ((parseInt($.browser.version) == 7) && (this.XMLHttpRequest)))
{ //Modification because of IE tester IE7 being detected as IE6
ret = true;
}
return ret;
}

The previous fiddle was not working in IEs because by the time the onblur() event fires, the selection is destroyed in IE. I have applied some browser based conditions for IE 6 and 7, but not tested yet in IE 8.

Thanks to Tim Down who helped me in identifying the problem with the previous fiddle.

Get non selected text from a textbox in IE

If I've understood your question correctly, you'll need something like this:

function getNonSelectedText(){
var elem=document.getElementById('input');
var selection=document.selection;
var range=selection.createRange();
if(range.boundingWidth<1){
return elem.value;
}
var rangePre=range.duplicate();
rangePre.moveToElementText(range.parentElement());// For <textarea>
// rangePre.expand('textedit'); // For <input type=text>
var rangePost=rangePre.duplicate();
rangePre.setEndPoint('EndToStart',range);
rangePost.setEndPoint('StartToEnd',range);
return rangePre.text+rangePost.text;
}

How do I get window.getselection to work for an input type=text field

In most browsers, window.getSelection() only works with selections within text nodes and elements within the document. It doesn't apply to text within <input> and <textarea> elements (although in WebKit window.getSelection().toString() will return the selected text within a focussed text input or textarea. See http://jsfiddle.net/PUdaS/). To get the selection within an input, use the input's selectionStart and selectionEnd properties:

<input type="text" id="test" value="Some text">

<input type="button" value="Click me"
onclick="alert(document.getElementById('test').selectionEnd);">

Note that IE up to and including version 8 does not support the selectionStart and selectionEnd properties, and a different, more complicated solution is required. IE doesn't support window.getSelection() either, so this code will work in all the browsers your original code does.



Related Topics



Leave a reply



Submit