I need to get the position of the selected text within a content non-editable div (not a textarea, not a rtf editor, just a simple div)
I want to do this in order to enable users to select pieces of an article and "highlight it", by wrapping it in a span with a different background and, of course, an article is build with divs and/or p-s etc, not textareas or rtfs
Any ideas?
P.s. You can also use jQuery :D
P.s.s. I need the position of the selection, not the selection itself. Aka: it start from index I to index J. I need this because the normal method of finding the text in the parent does not always return a unique result, which would suck :)
If you just want to change the background of the selected text, the easiest way to do this is by using document.execCommand(). See my answer here: Change CSS of selected text using Javascript
//Wrap selected text in span tags with the class 'hl'
//Take some action after (in this case, a simple alert)
$("p").live("mouseup",
function() {
selection = getSelectedText();
if(selection.length >= 3) {
$(this).html($(this).html().replace(selection, $('<\/span>').attr({'class':'hl'}).html(selection).parent().html()) );
alert(selection);
}
}
);
//Grab selected text
function getSelectedText(){
if(window.getSelection){
return window.getSelection().toString();
}
else if(document.getSelection){
return document.getSelection();
}
else if(document.selection){
return document.selection.createRange().text;
}
}
Code comes from here: http://esbueno.noahstokes.com/post/92274686/highlight-selected-text-with-jquery
You can check if text is selected by running :
window.getSelection and document.getSelection() and document.selection
(because browsers can check this i different ways)
and then search for div containing this text .
For getting the position of the selection, try these links:
http://bytes.com/topic/javascript/answers/153164-return-selectionstart-div
Set cursor position on contentEditable <div>
Well, even though you found a solution to the problem stated in your 2nd paragraph, i don't think the answer to your main question has been given. :)
The object Selection has a property named anchorOffset, giving exactly what you asked for (the position of the selected text within an element). The above link will tell you about which browsers support it, i'm afraid IE <9 might not.
function show_selected()
{
var sel = selection();
console.log(sel.anchorOffset + ':' + sel);
}
Now if you bind show_selected to, say, mouseup, you will see the offset and the selected text printed on the js console.
The fonction selection may be the following, supposed to be cross-browser:
function selection()
{
var sel;
if(window.getSelection){
sel = window.getSelection()
}
else if(document.getSelection){
sel = document.getSelection()
}
else if(document.selection){
sel = document.selection.createRange()
}
return sel
}
Related
As the rangy library says that, we need to select text to make it highlight and remove highlight.
For highlighting it includes span tag.
For removing highlight text I want to click on span tag instead of select that text.
this is library method is used to remove highlight:
unhighlightSelection: function(selection) {
selection = selection || api.getSelection();
console.log(selection.getAllRanges())
var intersectingHighlights = this.getIntersectingHighlights( selection.getAllRanges() );
this.removeHighlights(intersectingHighlights);
selection.removeAllRanges();
return intersectingHighlights;
}
here selection variable occupied with api.getSelection() instead of local selection variable.
I think it's sufficient to all of you to understand my problem.
I can give more description about that if you want.
Can I do something that to occupied the selection variable same as api.getSelection() without using it?
or what I do to achieve it?
Any suggestion will be grateful for me.
Thank you
Assuming that what you want is to be able to click on a highlight to get rid of it, I suggest something like the following (which has support for IE 6-8; I don't know whether you need that but Rangy supports it). The crucial methods are the getHighlightForElement() and removeHighlights():
document.onclick = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
var highlight = highlighter.getHighlightForElement(target);
if (highlight) {
highlighter.removeHighlights( [highlight] );
}
};
I'm trying to replace selected text with another text with a function switchText called from the context menu.
function switchText(info) {
var text = info.selectionText; // selected text
// then I do some manipulations with 'text' and get 'text_to_replace'
var text_to_replace = "some text"; // text to replace
}
alert(text) and alert(text_to_replace) works fine, but I'm trying to replace selected text right on the page but I can't figure out how to do it. I tried different methods but they hadn't worked. Any special permissions needed? I'm sorry if it's stupid question, I'm beginner in JS.
If you want to be able to do this anywhere on a page, you need to be able to set some kind of identifying ID to your selection. You have to do this through a content script of some kind. You can read more about it in the Chrome Developer documentation.
This code will allow you to change the text of a single selection
(tested in Chrome only)
function switchText(id) {
// Gets the selection range
// This is from Tim Down, linked below
var range, sel = window.getSelection();
if (sel.rangeCount && sel.getRangeAt) {
range = sel.getRangeAt(0);
}
// Creates a new node range
document.designMode = "on";
if (range) {
sel.removeAllRanges();
sel.addRange(range);
}
// This is from user YeppThatsMe, also linked below
document.execCommand("insertHTML", false, "<span id='own-id'>"+ document.getSelection()+"</span>");
document.designMode = "off";
// You can use either a variable or a string
var someNewText = "-- You can make this whatever you want --";
// Finds the new span and replaces the selection with your new text
document.getElementById("own-id").innerHTML=someNewText;
};
Sourced scripts
Tim's script
HTML5 inserCommand
Last Note
I didn't spend too long testing, and the script as-is will only change one selection per page. You'll need to tweak the way the function gets the tag and attribute info (change it to getElementsByClassName?) to run it more than once, but this should work.
to update a html element targeted by Id
document.getElementById("idtotarget").innerHTML = switchText(document.getElementById("idtotarget").innerHTML)
I need to highlight a selected text with JavaScript (no jQuery) and having control points or markers (left and right), I don't really know how to call them, similarly like on mobile phones so I can extend the selection anytime by dragging any of the control points.
Example: http://screencast.com/t/KJBdvreeVW
I've grabbed the selected text, demo: http://jsfiddle.net/henrichro/HJ482/
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
alert(text);
}
if (window.Event) document.captureEvents(Event.MOUSEUP);
document.onmouseup = getSelectionText;
Now I have this working code to get the text, but I would like to have markers around it, as written above :)
Update 10/28/2013:
After Dementic's directions (his answer below), I figured out the next working code: http://jsfiddle.net/henrichro/WFLU9/
The only problem persists when I select more than one line. On that scenario the markers are showing wrong.
found a solution here : How do I wrap a text selection from window.getSelection().getRangeAt(0) with an html tag?
which uses just a bit of Jquery, modified it so its pure js (just removed the selectors and the onclick), you can find a working example here:
http://jsfiddle.net/3tvSL/83/
this marks the selected text with yellow background, and will need a bit more work to have "Markers" on the sides.
as for an idea, you can use an absolute positioned div as the marker,
and while it is dragged, you can use something like:
function expand(range) {
if (range.collapsed) {
return;
}
while (range.toString()[0].match(/\w/)) {
range.setStart(range.startContainer, range.startOffset - 1);
}
while (range.toString()[range.toString().length - 1].match(/\w/)) {
range.setEnd(range.endContainer, range.endOffset + 1);
}
}
Taken from: Select whole word with getSelection
one more thing,
i have found a working js library to do exactly what you wish...
http://www.mediawiki.org/wiki/Extension:MashaJS
take a look :)
Is it possible to use or adapt jQuery's .select() to set a selection range on the entire contents of a div?
I have a div which has a series of labels, inputs, select objects and a couple of other UI elements. I have found code on a separate StackOverflow post with some code hosted on jsFiddle: http://jsfiddle.net/KcX6A/570/
Can this be adapted to select the value of inputs also? Or how would you suggest I go about this?
Thanks,
Conor
Edit: More info
I know how to get the value of inputs using jQuery, that is easy, I also know how to select he values of independent elements using .select().
In my div I have a series of different element types including inputs, labels, selects, etc. I need an overall selection of all elements. The jsFiddle link I added earlier shows how to set the range of a div and select the text of elements like p tags etc. What I need is to set the range of the div's contents and when I hit ctrl+c or cmd+c it copies the values of the inputs as well as the labels.
So to summarise, using .val and .select won't work for this I don't think. I need to combine the above in some way but not sure exactly how this will be accomplished. Any ideas?
Check this fiddle: http://jsfiddle.net/JAq2e/
Basically the trick is to introduce a hidden text node whose content will be included in the selection when copied.
jQuery.fn.selectText = function(){
this.find('input').each(function() {
if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) {
$('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
}
$(this).prev().html($(this).val());
});
var doc = document;
var element = this[0];
console.log(this, element);
if (doc.body.createTextRange) {
var range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
};
And use it like:
$('#selectme').selectText();
You can couple the above plugin with an event handler if you want to create selection links :
Code :
$('.select-text').on('click', function(e) {
var selector = $(this).data('selector');
$(selector).selectText();
e.preventDefault();
});
Usage :
Select all
<div id="some-container">some text</div>
Demo : see js fiddle
If you want to select the input elements together with every thing.
Here is a jQuery mixed, JS solution
function selectElement(element) {
if (window.getSelection) {
var sel = window.getSelection();
sel.removeAllRanges();
var range = document.createRange();
range.selectNodeContents(element);
sel.addRange(range);
} else if (document.selection) {
var textRange = document.body.createTextRange();
textRange.moveToElementText(element);
textRange.select();
}
}
selectElement($("div")[0]); //Select the div
$("input").trigger("select"); //select the inputs
Demo
If you want to select inside form elements. Use .focus() /.blur() and .val() functions.
$('input').focus(); //focus on input element
$('input').val(); //return the value of input
Not really. In most browsers it's not possible for the contents of more than one input to be selected at once. See http://jsfiddle.net/timdown/D5sRE/1/
So I feel like I'm a bit out of my league here. But here's what I want to do.
Basically, I want to have a user select part of text within in a paragraph (which may contain many elemnts (i.e. <span> and <a>) to return the value of the id attribute of that paragraph. Here's what I thinking.
function getParaID() //function will be called using a mouseUp event
{
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0); //btw can anyone explain what this zero means
var paraElement = selRange.commonAncestorContainer;
var paraID = paraElement.getAttribute;
return paraID;
}
What do you think? Am I close?
The selection range's commonAncestorContainer property may be a reference to a text node, or a <span> or <a> element or <body> element, or whatever else you may have in your page. That being the case, you need to work up the DOM tree to find the containing <p> element, if one exists. You also need to be aware that IE < 9 does not support window.getSelection() or DOM Range, although it is possible to do what you want quite easily in IE < 9. Here's some code that will work in all major browsers, including IE 6:
jsFiddle: http://jsfiddle.net/44Juf/
Code:
function getContainingP(node) {
while (node) {
if (node.nodeType == 1 && node.tagName.toLowerCase() == "p") {
return node;
}
node = node.parentNode;
}
}
function getParaID() {
var p;
if (window.getSelection) {
var selObj = window.getSelection();
if (selObj.rangeCount > 0) {
var selRange = selObj.getRangeAt(0);
p = getContainingP(selRange.commonAncestorContainer);
}
} else if (document.selection && document.selection.type != "Control") {
p = getContainingP(document.selection.createRange().parentElement());
}
return p ? p.id : null;
}
Regarding the 0 passed to getRangeAt(), that is indicating which selected range you want. Firefox supports multiple selected ranges: if you make a selection and then hold down Ctrl and make another selection, you will see you now have two discontinous ranges selected, which can be accessed via getRangeAt(0) and getRangeAt(1). Also in Firefox, selecting a column of cells in a table creates a separate range for each selected cell. The number of selected ranges can be obtained using the rangeCount property of the selection. No other major browser supports multiple selected ranges.
You're quite close. If all you want is the id of the parent element, then you should replace your paraElement.getAttribute with paraElement.id, like:
var paraID = paraElement.id;
Regarding the parameter to getRangeAt(), it is specifying the index of the selection range to return, and it's only really relevant to controls that allow discontinuous selections. For instance, a select box in which the user can use ctrl + click to select several arbitrary groups of rows simultaneously. In such a case you could use the parameter to step from one selected region to the next. But for highlighting text within a paragraph you should never have a discontinuous selection and thus can always pass 0. In essence it means that you're asking for "the first selected region".
Also note that if your interface allows the user's selection to span multiple paragraphs then your commonAncestorContainer may not be a paragraph, it might also be whatever element it is that contains all of your paragraph tags. So you should be prepared to handle that case.
Edit:
After playing with this a bit, here is my suggestion: http://jsfiddle.net/vCsZH/
Basically, instead of relying on commonAncestorContainer this code applies a mouseDown and a mouseUp listener to each paragraph (in addition to the one already applied to the top-level container). The listeners will, in essence, record the paragraphs that the selection range starts and ends at, making it much simpler to reliably work out which paragraph(s) are selected.
If ever there was a case in favor of using dynamic event binding through a framework like jQuery, this is it.