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?
Related
I'm creating a markdown editor and I need to check if neighbor characters are specific characters, then remove them, else append them.
For e.g I want to check selected-text, tow neighbor characters are **, then remove them, else append them around selected text.
I can get selected text using this approach:
function getSelection(elem) {
var selectedText;
if (document.selection != undefined) { // IE
elem.focus();
var sel = document.selection.createRange();
selectedText = sel.text;
} else if (elem.selectionStart != undefined) { // Firefox
var startPos = elem.selectionStart;
var endPos = elem.selectionEnd;
selectedText = elem.value.substring(startPos, endPos)
}
return selectedText;
}
$(document).on('mousedown', 'button', function(e) {
var selection = getSelection( $('#txtarea').get(0) );
alert(selection);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="txtarea">this is a test</textarea>
<button>Bold (toggle)</button>
Now I need when user clicks on that button, it checks if selected text is between ** like this **selectedtext**, then remove them like this selected text else append them like this **selectedtext**. How can I do that?
Before anything I would like to refer to all the markdown editors out there: https://www.google.de/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=javascript%20markdown%20library
So: do not try to reinvent the the wheel, and so on.
But for the sake of learning, my approach would look like this:
function toggleMarker(marker, el) {
var markerLength = marker.length;
var startPos, endPos, selection, range;
if (document.selection != undefined) { // IE
el.focus();
range = document.selection.createRange();
selection = range.text;
} else if (el.selectionStart != undefined) { // Firefox
startPos = el.selectionStart;
endPos = el.selectionEnd;
selection = el.value.substring(startPos, endPos);
}
if (!selection.length){
return;
}
if (el.value.substring(startPos-markerLength,startPos) === marker
&& el.value.substring(endPos,endPos+markerLength) === marker
){
el.value = el.value.substring(0,startPos-markerLength) +
selection +
el.value.substring(endPos+markerLength);
}
else{
el.value = el.value.substring(0,startPos) + marker +
selection + marker + el.value.substring(endPos);
}
}
$(document).on('mousedown', 'button', function(e) {
toggleMarker( $(this).data('marker'), $('#txtarea').get(0) ).text;
});
See it in action: https://jsfiddle.net/t4ro53v8/4/
The solution takes a very generic approach: the marker to toggle is set as a custom data attribute to make it easy to reuse the code.
The functionality is only implemented for the non-IE case. You will have to check, how to determine startPos and endPos for a range in IE.
In all other browsers:
the selection is identified
nothing is done if nothing is selected
sourroundings of the selection are checked against the given marker
if both markers are present, they get deleted
otherwise the markers are inserted
As a proof of concept this example works like a charm.
But there are some shortcomings:
How to distinguish between bold text(**) and italics(*)?
How to handle markers that just appear just on one side of the selection
What to do, if a marker is selected?
But that is for you to solve now ...
You could use regex to find the occurance of a ** ** pattern.This regex will help you find the pattern similar to what you have.
[*][*][a-z]*[*][*] .
Using the exec() method, will help you extract that particular text.
Check the length of this using .length, if it is 4, then there is nothing in between, and you can replace it with the new text surrounded by **,
"**"+ newtext+"**"
For removing the **, you can use the replace() method, where you replace ** with whitespace or so.
I'm working on a blog where I want a section to add a post. I'm imagining it very similar to the StackExchange editor I'm using right now to write this post.
I've managed to work with the textarea to get things like current caret position, insert at position, etc.
The problem I'm running into now is not losing the highlighted text in the textarea when the user clicks on another element, ie: the bold tool.
By default (at least in Chrome) when you highlight text in a textarea and then click elsewhere on the page, the textarea loses focus and the highlighted text with it.
When the textarea loses focus it will by default lose any previous selection, so at the onblur event you can save the current selection using the following function:
function getSelectedText() {
var txtarea = document.getElementById(textBoxScript);
var start = txtarea.selectionStart;
var finish = txtarea.selectionEnd;
var sel = txtarea.value.substring(start, finish);
return sel;
}
And to set it back on focus event you can use the following function:
function selectText(startPos, endPos, tarea) {
// Chrome / Firefox
if (typeof (tarea.selectionStart) != "undefined") {
tarea.focus();
tarea.selectionStart = startPos;
tarea.selectionEnd = endPos;
return true;
}
// IE
if (document.selection && document.selection.createRange) {
tarea.focus();
tarea.select();
var range = document.selection.createRange();
range.collapse(true);
range.moveEnd("character", endPos);
range.moveStart("character", startPos);
range.select();
return true;
}
}
I am trying to create a very basic rich-text editor in JavaScript but I'm having an issue with selections. So basically, since it's a contentEditable <div>, any time the user pastes in pre-formatted text from a webpage, the formatting doesn't get stripped off.
An easy to break hack is to give focus to a <textarea> upon Ctrl + V being pressed, so the text gets pasted in there, then onkeyup, give focus back to the <div>, copy the contents over and delete whatever went in to the <textarea>.
So that's easy, but when I give focus back to the contentEditable &;t;div>, the caret position is at the beginning and not immediately after the paste. I don't know enough about selections and whatnot to figure it out, so I'd appreciate some help. Here's my code:
// Helpers to keep track of the length of the thing we paste, the cursor position
// and a temporary random number so we can mark the position.
editor_stuff =
{
cursor_position: 0,
paste_length: 0,
temp_rand: 0,
}
// On key up (for the textarea).
document.getElementById("backup_editor").onkeyup = function()
{
var main_editor = document.getElementById("question_editor");
var backup_editor = document.getElementById("backup_editor");
var marker_position = main_editor.innerHTML.search(editor_stuff.temp_rand);
// Replace the "marker" with the .value of the <textarea>
main_editor.innerHTML = main_editor.innerHTML.replace(editor_stuff.temp_rand, backup_editor.value);
backup_editor.value = "";
main_editor.focus();
}
// On key down (for the contentEditable DIV).
document.getElementById("question_editor").onkeydown = function(event)
{
key = event;
// Grab control + V end handle paste so "plain text" is pasted and
// not formatted text. This is easy to break with Edit -> Paste or
// Right click -> Paste.
if
(
(key.keyCode == 86 || key.charCode == 86) && // "V".
(key.keyCode == 17 || key.charCode == 17 || key.ctrlKey) // "Ctrl"
)
{
// Create a random number marker at the place where we paste.
editor_stuff.temp_rand = Math.floor((Math.random() * 99999999));
document.getElementById("question_editor").textContent += editor_stuff.temp_rand;
document.getElementById("backup_editor").focus();
}
}
So my thinking is to store the cursor position (integer) in my helper array (editor_stuff.cursor_position).
N.B. I've been looking at other answers on SO all day and can't get any of them to work for me.
Here's a function that inserts text at the caret position:
Demo: http://jsfiddle.net/timdown/Yuft3/2/
Code:
function pasteTextAtCaret(text) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var textNode = document.createTextNode(text);
range.insertNode(textNode);
// Preserve the selection
range = range.cloneRange();
range.setStartAfter(textNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
document.selection.createRange().text = text;
}
}
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();
}
}
}
From my previous question for selecting specific html text, I have gone through this link to understand range in html string.
For selecting a specific text on html page. We need to follow this steps.
Assumed HTML:
<h4 id="entry1196"><a
href="http://radar.oreilly.com/archives/2007/03/call_for_a_blog_1.html"
class="external">Call for a Blogger's Code of Conduct</a></h4>
<p>Tim O'Reilly calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your tolerance level for abusive comments.</li>
<li>Consider eliminating anonymous comments.</li>
</ol>
java script to make selection by range
var range = document.createRange(); // create range
var startPar = [the p node]; // starting parameter
var endLi = [the second li node]; // ending parameter
range.setStart(startPar,13); // distance from starting parameter.
range.setEnd(endLi,17); // distance from ending parameter
range.select(); // this statement will make selection
I want to do this in invert way. I mean, assume that selection is done by user on browser (safari). My question is that How can we get starting node (as we have 'the p node' here) and ending node (as we have 'the second li node' here) and the range as well (as we have 13,17 here)?
Edit : my efforts (From this question)
var sel = window.getSelection();
if (sel.rangeCount < 1) {
return;
}
var range = sel.getRangeAt(0);
var startNode = range.startContainer, endNode = range.endContainer;
// Split the start and end container text nodes, if necessary
if (endNode.nodeType == 3) {
endNode.splitText(range.endOffset);
range.setEnd(endNode, endNode.length);
}
if (startNode.nodeType == 3) {
startNode = startNode.splitText(range.startOffset);
range.setStart(startNode, 0);
}
But, yet I am confused about getting like, if selected is first paragraph or second or third, or selected is in first heading or second heading or what....
Storing the selected range is simple. The following will return only the first selected range (Firefox at least supports multiple selections):
<script type="text/javascript">
function getSelectionRange() {
var sel;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (document.selection) {
return document.selection.createRange();
}
return null;
}
var range;
</script>
<input type="button" onclick="range = getSelectionRange();"
value="Store selection">
range will have properties startContainer (the node containing the start of the range), startOffset (an offset within the start container node: a character offset in the case of text nodes and child offset in elements), endContainer and endOffset (equivalent behvaiour to the start properties). Range is well documented by its specification and MDC.
In IE, range will contain a TextRange, which works very differently. Rather than nodes and offsets, TextRanges are concerned with characters, words and sentences. Microsoft's site has some documentation: http://msdn.microsoft.com/en-us/library/ms533042%28VS.85%29.aspx, http://msdn.microsoft.com/en-us/library/ms535872%28VS.85%29.aspx.