I'm looking to move the caret exactly four spaces ahead of its current position so that I can insert a tab properly. I've already got the HTML insertion at the caret's position working, but when I insert the HTML, the caret is left behind. I've spent the past hour or so looking at various ways to do this and I've tried plenty of them, but I can't get any of them to work for me. Here's the most recent method I've tried:
function moveCaret(input, distance) {
if(input.setSelectionRange) {
input.focus();
input.setSelectionRange(distance, distance);
} else if(input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd(distance);
range.moveStart(distance);
range.select();
}
}
It does absolutely nothing--doesn't move the caret, throw any errors or anything. This leaves me baffled. And yes, I know that the above method set (is supposed to) set the caret at a certain position from the beginning of the specified node (that is, input), but even that's not working. So, what exactly am I doing wrong, and how can I do it right?
Edit: Based on the links that o.v. provided, I've managed to cobble something together that's finally doing something: throwing an error. Yay! Here's the new code:
this.moveCaret = function(distance) {
if(that.win.getSelection) {
var range = that.win.getSelection().getRangeAt(0);
range.setStart(range.startOffset + distance);
} else if (that.win.document.selection) {
var range = that.win.document.selection.createRange();
range.setStart(range.startOffset + distance);
}
}
Now, this gives the error Uncaught Error: NOT_FOUND_ERR: DOM Exception 8. Any ideas why?
The code snippet you have is for text inputs and textareas, not contenteditable elements.
Provided that all your content is in a single text node and the selection is completely contained within it, the following will work in all major browsers, including IE 6.
Demo: http://jsfiddle.net/9sdrZ/
Code:
function moveCaret(win, charCount) {
var sel, range;
if (win.getSelection) {
// IE9+ and other browsers
sel = win.getSelection();
if (sel.rangeCount > 0) {
var textNode = sel.focusNode;
var newOffset = sel.focusOffset + charCount;
sel.collapse(textNode, Math.min(textNode.length, newOffset));
}
} else if ( (sel = win.document.selection) ) {
// IE <= 8
if (sel.type != "Control") {
range = sel.createRange();
range.move("character", charCount);
range.select();
}
}
}
Related
I have found a code snippet (can't remember where), and it's working fine - almost :-)
The problem is, that it copies the selection no matter where the selection is made on the entire website, and it must only copy the selection if it is in a specific div - but how is that done?
function getHTMLOfSelection () {
var range;
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
return range.htmlText;
}
else if (window.getSelection) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
range = selection.getRangeAt(0);
var clonedSelection = range.cloneContents();
var div = document.createElement('div');
div.appendChild(clonedSelection);
return div.innerHTML;
} else {
return '';
}
} else {
return '';
}
}
$(document).ready(function() {
$("#test").click(function() {
var kopitekst = document.getElementById("replytekst");
var kopitjek=getHTMLOfSelection(kopitekst);
if (kopitjek=='')
{
alert("Please select some content");
}
else
{
alert(kopitjek);
}
});
});
I have made a Jsfiddle
This is my first post here. Hopefully I done it right :-)
That's because it checks the entire document with:
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
return range.htmlText;
}
Not a specific section. If you want to check specific sections for selected text, you need to identify that you are searching for them in the search selection, something that nails your range down to a particular div:
range = $('#replytekst');
Specify a particular DOM element instead of using document object.
var oDiv = document.getElementById( 'selDiv' );
then use
if ( oDiv.selection && oDiv.selection.createRange ) {
range = oDiv.selection.createRange();
return range.htmlText;
}
You need to check if the section contains the selection. This is separate from getting the selection. There is a method for doing this in this answer: How to know if selected text is inside a specific div
I've updated your fiddle
Basically you need to check the id of the parent/ascendant of the selected text node.
selection.baseNode.parentElement.id or selection.baseNode.parentElement.parentElement.id will give you that.
Edit: I've thought of another, somewhat hack-y, way of doing it.
If
kopitekst.innerHTML.indexOf(kopitjek) !== -1
gives true, you've selected the right text.
DEMO1
DEMO2
(these work in Chrome and Firefox, but you might want to restructure the getHTMLOfSelection function a little)
If it possible for you I recommend to use rangy framework. Then your code might look like this:
// get the selection
var sel = rangy.getSelection();
var ranges = sel.getAllRanges();
if (!sel.toString() || !sel.toString().length)
return;
// create range for element, where selection is allowed
var cutRange = rangy.createRange();
cutRange.selectNode(document.getElementById("replytekst"));
// make an array of intersections of current selection ranges and the cutRange
var goodRanges = [];
$.each(ranges, function(j, tr) {
var rr = cutRange.intersection(tr);
if (rr)
goodRanges.push(rr);
});
sel.setRanges(goodRanges);
// do what you want with corrected selection
alert(sel.toString());
// release
sel.detach();
In this code if text was selected in your specific div then it will be kept, if there was selection where other elements take part too, these selection ranges will be cut off.
I know it's pretty easy to focus an input using JavaScript/ jQuery, but is it possible to focus the input on a certain character?
So take this input:
Would it be possible to focus the element and have the cursor be placed after the first sentence, for example?
Sure :
$('#inputID').focus().get(0).setSelectionRange(12, 12);
works in most browsers, but older IE uses createTextRange and move().
FIDDLE
EDIT:
five minute plugin:
$.fn.setCaret = function(pos) {
return this.each(function() {
var elem = this,
range;
if (elem.createTextRange) {
range = elem.createTextRange();
range.move('character', pos);
} else {
if (elem.selectionStart !== undefined) {
elem.setSelectionRange(pos, pos);
}
}
});
}
to be called like:
$('#inputID').focus().setCaret(12);
FIDDLE
Hey, so I'm working with ranges, I'm trying to limit the selection an user can make on the page. What I mean is the user can select whatever he wants, but the selection cannot exceeds the boundaries I will set.
First I define the "boundaries" with a defined range. Then I compare the current user selection with the defined range, if the current selection start is below the boundaries OR the current selection end is above the boundaries I adjust accordingly so the user selection never exceeds the defined boundaries range/selection.
The function below only works If I output an alert before the process starts, If I remove the alert, then firefox behaves weird (Like selecting another part of the page, etc.)
The question is: Why the following code works with an alert and why it doesn't work as expected without the alert?
Thanks!
var range = document.createRange(); // this is the boundaries range
range.selectNodeContents(document.getElementById("container"));
function test(){
alert("let's go"); // if I remove this alert, the code doesn't work as expected, WHY?!
if(window.getSelection().rangeCount == 0){
return;
}
var curRange = window.getSelection().getRangeAt(0);
if(curRange.compareBoundaryPoints(Range.START_TO_START, range) < 0){
curRange.setStart(range.startContainer,range.startOffset);
}
if(curRange.compareBoundaryPoints(Range.END_TO_END, range) > 0){
curRange.setEnd(range.endContainer,range.endOffset);
}
}
Firstly, to work in other browsers (except IE <= 8, which has a totally different way of doing this stuff) you'll need to reselect the range. Secondly, to make it work in Firefox, you need to work on a clone of the original selected range:
function test(){
var sel = window.getSelection();
if (sel.rangeCount == 0) {
return;
}
var curRange = sel.getRangeAt(0).cloneRange();
if (curRange.compareBoundaryPoints(Range.START_TO_START, range) < 0) {
curRange.setStart(range.startContainer,range.startOffset);
}
if (curRange.compareBoundaryPoints(Range.END_TO_END, range) > 0) {
curRange.setEnd(range.endContainer,range.endOffset);
}
sel.removeAllRanges();
sel.addRange(curRange);
}
I have these two codes -
new function($) {
$.fn.getCursorPosition = function() {
var pos = 0;
var el = $(this).get(0);
// IE Support
if (document.selection) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
// Firefox support
else if (el.selectionStart || el.selectionStart == '0')
pos = el.selectionStart;
return pos;
}
} (jQuery);
And
var element = document.getElementById('txtarr');
if( document.selection ){
// The current selection
var range = document.selection.createRange();
// We'll use this as a 'dummy'
var stored_range = range.duplicate();
// Select all text
stored_range.moveToElementText( element );
// Now move 'dummy' end point to end point of original range
stored_range.setEndPoint( 'EndToEnd', range );
// Now we can calculate start and end points
element.selectionStart = stored_range.text.length - range.text.length;
element.selectionEnd = element.selectionStart + range.text.length;
}
The first one is for getting the cursor position in a textarea and the second one is for determining the end of a textarea ,but they give the same result?
Where's the mistake?
I fix it.It's very simple :) .
I just replace the second code(for determining the end of the textarea) with:$("#txtarr").val().length(jQuery).#txtarr is the id of mine textarea.
Both pieces of code are doing the same thing in slightly different ways. Each is attempting to get the position of the caret or selection in a textarea (or text input), although the first only gets the start position of the selection while the second gets both the start and end positions.
Both have flaky inferences: the first assumes a browser featuring document.selection will support TextRange, while the second makes the same inference plus another that assumes a browser without support for document.selection will have support for selectionStart and selectionEnd properties of textareas. Neither will correctly handle line breaks in IE. For code that does that, see my answer here: How to get the start and end points of selection in text area?
I wanna modify the document selection (user currently selected by mouse or keyboard), how to do it in a cross browser way?
I have not worked with text selection enough to provide real help, but what you are trying to do can be done. You will want to look into the following two functions:
createRange() MSDN | MDC
getRangeAt() MDC
I know it can be implemented cross browser. You can see some of it in action here:
http://fuelyourcoding.com/a-few-strategies-for-using-javascript/
By scrolling to the bottom and clicking the Elephant Icon, which uses the Evernote script. However, my script first selects the main content area (you will see it flash orange) and then it deselects once the capture is made.
Here is a mini jQuery plugin that does it. It was adapted by me from some site, and like the comments say, I feel horrible for not remembering. Its really important to note I adapted it to jQuery, but the code came from some site where they explained how to do it:
// Adapted this from somewhere. Feel horrible for not remembering.
$.fn.autoSelect = function(){
var selectTarget = this[0]; // Select first element from jQuery collection
if(selectTarget != null) {
if(selectTarget.tagName == 'TEXTAREA' || (selectTarget.tagName == "INPUT" && selectTarget.type == "text")) {
selectTarget.select();
} else if(window.getSelection) { // FF, Safari, Opera
var sel = window.getSelection();
var range = document.createRange();
range.selectNode(selectTarget);
sel.removeAllRanges();
sel.addRange(range);
} else { // IE
document.selection.empty();
var range = document.body.createTextRange();
range.moveToElementText(selectTarget);
range.select();
};
};
return this; // Don't break the chain
};
It seems this script is a few places online, but here is another variation on it
As an example, and the easiest one, let's say you want to move the user's selection to contain the contents of an element. The following will work in all major browsers:
function selectElementContents(el) {
var body = document.body, range, sel;
if (body.createTextRange) {
range = body.createTextRange();
range.moveToElementText(el);
range.select();
} else if (document.createRange && window.getSelection) {
range = document.createRange();
range.selectNodeContents(el);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
}
selectElementContents( document.getElementById("someElement") );