Finding indices of highlighted text - javascript

I'm trying to save information about text that a user has highlighted in a webpage. Currently I'm using the getSelection method shown below:
var txt = '';
if (window.getSelection){txt = window.getSelection();}
else if (document.getSelection){txt = document.getSelection();}
else if (document.selection){txt = document.selection.createRange().text;}
else return;
to retrieve the highlighted text. Then I'm searching through the entire text body and storing the indices of the highlighted text. The getSelection method only returns what text is highlighted so the problem is that if the highlighted text appears multiple times in the text body, the search could find the wrong repeat of the text and thus save the wrong indices.
Any ideas how to ensure that I'm saving the right indices?
Thanks!

QuirksMode has an article about this.
You'd probably be interested in this code:
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
else if (document.selection) { // should come last; Opera!
userSelection = document.selection.createRange();
}
var rangeObject = getRangeObject(userSelection);
function getRangeObject(selectionObject) {
if (selectionObject.getRangeAt)
return selectionObject.getRangeAt(0);
else { // Safari!
var range = document.createRange();
range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);
return range;
}
}

Related

Javascript edit text in selection via Bookmarklet

I am trying to make a simple bookmarklet (bookmark with javascript applet) that will get the selected text, reverse it, and then change it on screen. For example, if the user selects some text, say, the word hello, and then activates this bookmarklet, the text would then turn into olleh. So far I have the following:
javascript:
function getSelectedText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
var selectedText = getSelectedText();
var textArray = selectedText.split("");
var reverseArray = textArray.reverse();
var reverseText = reverseArray.join("");
alert(reverseText);
I got the getSelectedText() function from here. At the end, the bookmarklet simply alerts the reversed text. How do you make it so that it actually replaces the text on the page? Thanks in advance for any possible help.
You can add this to the end:
var nodeValue = window.getSelection().baseNode.nodeValue;
window.getSelection().baseNode.nodeValue = nodeValue.replace(selectedText, reverseText);
EDIT
Use selection offset for reversing in the right place, str.replace only replaces the first occurrence of the word, and it can be wrong for common words such as "the".
var selection = window.getSelection();
var start = selection.anchorOffset;
var end = selection.focusOffset;
var nodeValue = selection.baseNode.nodeValue;
var newValue = nodeValue.slice(0, start) + reverseText + nodeValue.slice(end);
window.getSelection().baseNode.nodeValue = newValue;

Highlight text in javascript like Evernote Web Clipper

My current solution is:
Get selected html (include text and html tag), namely: selText
highlightText = <span>selText</span>
Find selText in innerHTML of the body or document (or the element which the mouse dragged in)
Replace with highlightText
But if the document is: a a a a a a and user selects the last a. My function will highlight the first or all a.
Any suggestion?
Thank you.
i think your question is duplicated, anyway i just searched the internet and found this article.
Below the final code to achieve what you ask
function highlightSelection() {
var selection;
//Get the selected stuff
if(window.getSelection)
selection = window.getSelection();
else if(typeof document.selection!="undefined")
selection = document.selection;
//Get a the selected content, in a range object
var range = selection.getRangeAt(0);
//If the range spans some text, and inside a tag, set its css class.
if(range && !selection.isCollapsed)
{
if(selection.anchorNode.parentNode == selection.focusNode.parentNode)
{
var span = document.createElement('span');
span.className = 'highlight-green';
range.surroundContents(span);
}
}
}
I also found this library rangy that is an helper you can use to select text but only works with jquery so i prefer the first vanilla-js solution.
var el = $("<span></span>");
el.text(rangy.getSelection().getRangeAt(0).toString());
rangy.getSelection().getRangeAt(0).deleteContents();
rangy.getSelection().getRangeAt(0).insertNode(el.get(0));
rangy.getSelection().getRangeAt(0).getSelection().setSingleRange(range);
On Range and User Selection
You have to select range using Document.createRange that return a Range object before you can use Range.surroundContents(), you could create a range this way.
var range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
In practice you follow this guide to understand range and selection tecniques.
The most important point is contained in this code
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
else if (document.selection) { // should come last; Opera!
userSelection = document.selection.createRange();
}
After this you can use
userSelection.surroundContents()

Store multiple text selections in localStorage

I'm working on a Chrome extension that allows a user to highlight text on a webpage. Simple, but it's to help me learn. Right now, I'm stuck and looking for how to best solve a problem.
Currently, I can highlight selected text that persists on the page.
JavaScript
function addHilite(color) {
var range, sel = window.getSelection();
if (sel.rangeCount && sel.getRangeAt) {
range = sel.getRangeAt(0);
}
document.designMode = "on";
if (range) {
sel.addRange(range);
};
if (!document.execCommand("hiliteColor", false, "#FFFF00")) {
document.execCommand("backColor", false, "#FFFF00");
}
document.designMode = "off";
console.log(range);
}
I'm trying to get to a point where the user could select a highlighted range and use the same browser action to undo a highlight. I thought localStorage would be a good way to save the state between each click, but I can't figure out how to store multiple ranges as a string for reference. Is there a better way to do this?
localStorage Experiment
function sel() {
var getText = window.getSelection().toString();
localStorage.setItem('getText', JSON.stringify(getText));
console.log(JSON.parse(localStorage.getItem('getText')));
}
do you mean something like this?
var selections = [];
function sel() {
var getText = window.getSelection().toString();
selections.push(getText);
localStorage.setItem('getText', selections);
console.log(localStorage.getItem('getText'));
}

Javascript find occurance position of selected text in a div

I have a string with a word five times.if i selected forth hello it should return 4
<div id="content">hello hai hello hello hello</div>
getting selected text script
<script>
if(window.getSelection){
t = window.getSelection();
}else if(document.getSelection){
t = document.getSelection();
}else if(document.selection){
t =document.selection.createRange().text;
}
</script>
If am selecting hai it should return 1.
If am selecting hello hai it should return 1. please help.
Assuming that the contents of the <div> are guaranteed to be a single text node, this is not too hard. The following does not work in IE < 9, which does not support Selection and Range APIs. If you need support for these browsers, I can provide code for this particular case, or you could use my Rangy library.
Live demo: http://jsfiddle.net/timdown/VxTfu/
Code:
if (window.getSelection) {
var sel = window.getSelection();
var div = document.getElementById("content");
if (sel.rangeCount) {
// Get the selected range
var range = sel.getRangeAt(0);
// Check that the selection is wholly contained within the div text
if (range.commonAncestorContainer == div.firstChild) {
// Create a range that spans the content from the start of the div
// to the start of the selection
var precedingRange = document.createRange();
precedingRange.setStartBefore(div.firstChild);
precedingRange.setEnd(range.startContainer, range.startOffset);
// Get the text preceding the selection and do a crude estimate
// of the number of words by splitting on white space
var textPrecedingSelection = precedingRange.toString();
var wordIndex = textPrecedingSelection.split(/\s+/).length;
alert("Word index: " + wordIndex);
}
}
}
You'll need to use the Range capabilities of the DOM. Here is how to get the currently selected range:
var currentRange = window.getSelection().getRangeAt(0);
From there currentRage.startOffset will tell you the position of your selection within the file. So you'll need to compare that with the start range of your element:
var myContent = document.getElementById('content');
var divRange = document.createRange ();
divRange.selectNodeContents (myContent);
Now you can compare the divRange.startOffset with your selection startOffset and determine which one you're on.

How do you manipulate selected text via a Firefox extension

I'm working on a Firefox extension that will manipulate highlighted text.
On a stand-alone page, I can get the selected text with:
selectedText = document.selection?document.selection.createRange().text;
Then I'd manipulate the selected text with string operations on the textarea in question. Unfortunately, that isn't possible for a plugin since I don't know where the user's selected text is.
Is there a way get the name of the element in which text is selected or to alter selected text without the name of the element?
selectedText = content.getSelection().toString();
you need to get the range object from your user selection:
var userSelection;
if (window.getSelection)
userSelection = window.getSelection();
else if (document.selection) // should come last; Opera!
userSelection = document.selection.createRange();
var rangeObject = getRangeObject(userSelection);
...
function getRangeObject(selectionObject) {
if (selectionObject.getRangeAt)
return selectionObject.getRangeAt(0);
else { // Safari!
var range = document.createRange();
range.setStart(selectionObject.anchorNode, selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode, selectionObject.focusOffset);
return range;
}
}
...
The Range object has start and end container nodes, etc ..
more information can be found on Quirksmode here and on w3.org here

Categories

Resources