Getting the parent node for selected text with rangy library - javascript

I'm using the rangy library and can select text in a content editable as follows:
var sel = rangy.getSelection();
alert(sel);
I can't figure out how to get the selected text parent node/element. For example, if I'm selecting text that is
<strong>My Text</strong>
or
<h1>My Title</h1>
how can I include the strong node or H1 element also?

sel.anchorNode.parentNode will get you the parent node of the node containing only one end of the selection. To get the innermost containing element for the whole selection, the easiest thing is to get a Range from the selection and look at its commonAncestorContainer property (which may be a text node, in which case you need to get its parent):
var sel = rangy.getSelection();
if (sel.rangeCount > 0) {
var range = sel.getRangeAt(0);
var parentElement = range.commonAncestorContainer;
if (parentElement.nodeType == 3) {
parentElement = parentElement.parentNode;
}
}

Related

How to check if selected text in html already has a class?

I'm making a function that takes a selected piece of text and highlights it by adding the tag. It highlights the text but if I click the highlight button again, the text disappears. Instead, I'd just want the text to go back to being un-highlighted. Anyone have suggestions how I could go about doing this?
highLightText() {
var selection = window.getSelection();
console.log('this is the selection: ', selection);
var selection_text = selection.toString();
var mark = document.createElement('mark');
mark.textContent = selection_text;
var range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(mark);
}
My idea was to somehow check if the selected text from var selection has an element named mark in it and if it does, don't continue with the rest of the function. I'm just not exactly sure how to implement it.
You can get a reference to the node that is currently selected by using the Selection's anchorNode or focusNode and from there get the parent element of the text.
var parent = selection.anchorNode.parentElement;
From there is it just a matter of checking it's nodeName property to see if it is mark.
parent.nodeName == "MARK" //nodeName is uppercase
After that just replace the mark element with the text node and call normalize() on the grand parent element to make sure any adjacent text nodes get merged
let grandParent = parent.parentElement;
parent.replaceWith(document.createTextNode(parent.textContent));
grandParent.normalize();
This will do all the text in the mark element and not just the selected text of a mark, for that you will have to modify the code if that was the intention.
Demo (hit any key after making a selection)
function highLightText() {
var selection = window.getSelection();
var parent = selection.anchorNode.parentElement;
var selection_text = selection.toString();
if (parent.nodeName == "MARK") {
let grandParent = parent.parentElement;
parent.replaceWith(document.createTextNode(parent.textContent));
grandParent.normalize();
return;
}
var mark = document.createElement('mark');
mark.textContent = selection_text;
var range = selection.getRangeAt(0);
range.deleteContents();
range.insertNode(mark);
}
document.addEventListener('keyup',highLightText);
<div>
<div>Test one two three</div>
<div>Test four five six</div>
<div>Test seven eight nine</div>
<div>Test ten eleven twelve</div>
</div>

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()

If text-selection is inside a specific div

I am using contenteditable=true trying make a text editor. I have successfully used getSelection() to wrap the selection inside HTML tags.
A problem is though, that if the user selects text outside the editor and the operation button is clicked, that text will be wrapped inside tags as well.
How would I do it with getSelection(), check if the selection is inside a div with the class of editor?
Edit:
Currently using this code:
var sel = window.getSelection ? window.getSelection() : document.selection.createRange();
if(sel.getRangeAt){
var range = sel.getRangeAt(0);
var newNode = document.createElement("p");
newNode.setAttribute('class', operationClass);
range.surroundContents(newNode);
} else {
sel.pasteHTML('<p class="' + operationClass +'">'+sel.htmlText+'</p>');
}
Once you have var range = sel.getRangeAt(0); you can determine if range.commonAncestorContainer or one of its ancestors is the editor container, using code like this:
var ancestor = range.commonAncestorContainer;
while (ancestor.id != "editor" // Check id, class or otherwise
&& ancestor.parentElement != null) {
ancestor = ancestor.parentElement;
}
if (ancestor.id == "editor") {
// Selection is within the editor.
}

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 to select a text range in CKEDITOR programatically?

Problem:
I have a CKEditor instance in my javascript:
var editor = CKEDITOR.instances["id_corpo"];
and I need to insert some text programatically, and select some text range afterwards.
I already did insert text through
editor.insertHtml('<h1 id="myheader">This is a foobar header</h1>');
But I need to select (highlight) the word "foobar", programatically through javascript, so that I can use selenium to work out some functional tests with my CKEditor plugins.
UPDATE 1:
I've also tried something like
var selection = editor.getSelection();
var childs = editor.document.getElementsByTag("p");
selection.selectElement(childs);
But doesn't work at all!
How can I do that?
I think that
selection.selectRange()
could do the job, but I'could not figure out how to use it.
There are no examples over there :(
Get current selection
var editor = CKEDITOR.instances["id_corpo"];
var sel = editor.getSelection();
Change the selection to the current element
var element = sel.getStartElement();
sel.selectElement(element);
Move the range to the text you would like to select
var findString = 'foobar';
var ranges = editor.getSelection().getRanges();
var startIndex = element.getHtml().indexOf(findString);
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + findString.length);
sel.selectRanges([ranges[0]]);
}
You can also do the following:
get the current selection
var selection = editor.getSelection();
var selectedElement = selection.getSelectedElement();
if nothing is selected then create a new paragraph element
if (!selectedElement)
selectedElement = new CKEDITOR.dom.element('p');
Insert your content into the element
selectedElement.setHtml(someHtml);
If needed, insert your element into the DOM (it will be inserted into the current position)
editor.insertElement(selectedElement);
and then just select it
selection.selectElement(selectedElement);
Check out the selectElement() method of CKEDITOR.dom.selection.
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dom.selection.html
insert text at cursor point in ck editor
function insertVar(myValue) {
CKEDITOR.instances['editor1'].fire( 'insertText',myValue);
}
this is working for me

Categories

Resources