Get HTML element contained in range - javascript

I am using document.getSelection() to select some text. I would like to know what type of element the selected range contains (I specifically want to see if it is an anchor tag).
var selection = document.getSelection();
var range = selection.getRangeAt(0);
So I can get the range, but how can I know what element is in that range? Happy to use plain js or jQuery.
EDIT:
Here is what I came up with:
var updateLink = function(url) {
var selection = document.getSelection();
var range = selection.getRangeAt(0);
if (range != 0) {
var containerElement = range.commonAncestorContainer;
if (containerElement.nodeType != 1) {
containerElement = containerElement.parentNode;
var e = $(containerElement);
e.attr('href', url);
}
}
}//end

Try this:
var obj = document.getSelection();
var parentNode = $(obj.anchorNode).parent();
Here is jsfiddle

You could use cloneContents() method:
DEMO
$(document).mouseup(function(){
var range = window.getSelection().getRangeAt(0),
selectionContents = range.cloneContents();
alert($(selectionContents.childNodes).filter('a').length);
});

Related

Replace text on gmail using js

I am working on a chrome extension, which replaces part of the text. It does not work as expected on Gmail though.
Scanario:
Gmail composer has following text -
i am now to this.
i can do this.
I want to replace it to -
i am new to this.
i can do this.
However, whenever I execute the code, it does not replace the text on the correct location.
It sees where my cursor was and appends the text there instead of replacing the intended text.
This snippet works on other websites, which have contenteditable editors.
My current implementation looks like the following:
const range = document.createRange();
const ele = <div tag element for 'i am now to this.' sentence>
// rangeStart and rangeEnd are the index which wraps word 'now'
range.setStart(ele.childNodes[0], rangeStart);
range.setEnd(ele.childNodes[0], rangeEnd);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
setTimeout(()=>{
document.execCommand(
"insertText",
false,
"new"
);
},0)
There are a couple of things that might go wrong about it.
One is that I noticed the div initially containing a single textNode with some text switched to a node containing multiple textNodes with exactly the same over all text and that can create a number of problems considering that you are operating only with children[0].
Another thing that didn't work for me was the document executing the isertText
How so ever something that worked for me:
var range = document.createRange();
var rangeStart = el.innerText.indexOf(s);
var rangeEnd = rangeStart + s.length;
var selection = window.getSelection();
range.setStart(el.childNodes[0], rangeStart);
range.setEnd(el.childNodes[0], rangeEnd);
selection.removeAllRanges();
selection.addRange(range);
range.deleteContents();
range.insertNode(document.createTextNode(ss))
My entire testing scenario:
(()=>{
var all = document.getElementsByTagName('div');
var n = all.length;
var find = (s)=>{
var result = [];
for (var i = 0; i < n; i++) {
var el = all[i];
var text = el && el.childNodes && el.childNodes[0] && el.childNodes[0].wholeText;
if (text && text.match(s)) {
result.push(el);
}
}
return result.length ? result : false;
}
;
var replacer = (s,ss)=>(el)=>{
try {
var range = document.createRange();
var rangeStart = el.innerText.indexOf(s);
var rangeEnd = rangeStart + s.length;
range.setStart(el.childNodes[0], rangeStart);
range.setEnd(el.childNodes[0], rangeEnd);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
range.deleteContents();
range.insertNode(document.createTextNode(ss))
}catch(ex){
}
}
;
var elements = find('now');
if (elements) {
elements.map(replacer('now', 'new'))
}
}
)(window);
Good luck :)

How we can get selected text start off set with respect to his parent element in java script?

I'm facing some problem in using javascript.The scenario is like html object has one parent element paragraph and 4 child element span . when we select text we are getting text position with respect to span element , but i want to get text selecting text with respect to parent so can you please guide me how i can?
I'm using this code that each time give position with respect to selected container like
<p>I'm using this code that each time<span>give position with respect to selected container like</span></html>
i want to get text position " respect" on upper code with respect to p tag not with repect to span tag.
var sel = window.getSelection();
var selRange = sel.getRangeAt(0);
var start = selRange.startContainer;
var startElemPath = pathOfElement(start);
var startoff = selRange.parentNode.startOffset;
alert("startoff>>"+startoff);
var end = selRange.endContainer;
var endElemPath = pathOfElement(end);
var endoff = selRange.endOffset;
You can use this process to get start off set and end off set of selected text.
function getCaretCharacterOffsetWithin(objectId, win)
{
var startOffSet = 0;
var endOffset = 0;
var element = window.frames[0].document.getElementById(objectId);
var parentInnerHTML = element.innerHTML.toString();
var parentNodeArr = parentInnerHTML.split('');
if(parentInnerHTML != "null"){
var sel;
if (typeof win.getSelection != "undefined")
{
var rangeIndex = 0;
var parentIndex = 0;
var max = parentInnerHTML.length - 1;
var range = win.getSelection().toString();
var rangeNodeArr = range.split('');
var rangeLen = rangeNodeArr.length - 1;
for (parentIndex=0; parentIndex <= max; parentIndex++)
{
if(parentNodeArr[parentIndex] === rangeNodeArr[rangeIndex]){
if(rangeIndex === rangeLen){
break;
}
rangeIndex++;
}else{
rangeIndex = 0;
}
}
endOffset = parentIndex + 1;
startOffSet = parentIndex - rangeIndex;
}
console.log("startOffSet: " + startOffSet + " endOffset: " + endOffset);
return { startOffSet: startOffSet, endOffSet: endOffset };
}else{
console.log("Parent is null");
}
}
try setting the Range's start node to p
startNode = document.getElementsByTagName("p")[0];
selRange.setStart(startNode,0);

How can I save a range object (from getSelection) so that I can reproduce it on a different page load?

I am trying to make a web app which allows the user to select some text on a page, and then with the click of another button highlight it. When the user goes back to the page, I want the highlight to show up in the same spot as well.
So I've gotten as far as:
var selectedRange = document.getSelection().getRangeAt(0);
highlightRange(selectedRange);
Where highlightRange is a function that highlights the range. This works so far.
The problem is, I need a way to save the selectedRange into a database so that it can be fetched again later. After that, I need to re-create the range from this data and highlight it again. I've found this method:
document.createRange();
From this page here: https://developer.mozilla.org/en-US/docs/Web/API/range
But I'm not really sure how I can make this work
UPDATE:
I know I'll need to re-create the range from scratch afterwards. And to do that I will use something like this:
var range = document.createRange();
range.setStart(startNode,startOffset);
range.setEnd(endNode,endOffset);
I can easily store startOffset and endOffset because those are just numbers. But startNode and endNode are node objects. I don't know how to store this in a database?
More specifically, I need to store the reference to the node in a database.
I solved this problem by saving 5 pieces of information from the range into the database:
var saveNode = range.startContainer;
var startOffset = range.startOffset; // where the range starts
var endOffset = range.endOffset; // where the range ends
var nodeData = saveNode.data; // the actual selected text
var nodeHTML = saveNode.parentElement.innerHTML; // parent element innerHTML
var nodeTagName = saveNode.parentElement.tagName; // parent element tag name
And then to build the range from the database, I have this function:
function buildRange(startOffset, endOffset, nodeData, nodeHTML, nodeTagName){
var cDoc = document.getElementById('content-frame').contentDocument;
var tagList = cDoc.getElementsByTagName(nodeTagName);
// find the parent element with the same innerHTML
for (var i = 0; i < tagList.length; i++) {
if (tagList[i].innerHTML == nodeHTML) {
var foundEle = tagList[i];
}
}
// find the node within the element by comparing node data
var nodeList = foundEle.childNodes;
for (var i = 0; i < nodeList.length; i++) {
if (nodeList[i].data == nodeData) {
var foundNode = nodeList[i];
}
}
// create the range
var range = cDoc.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
return range;
}
From there, I can just use my highlightRange function again to highlight the text.
Update 2022-01
Didn't know this was actually still being used. Thought I might as well give two cents about the two for loops and how we can improve them with modern syntax:
const foundEle = tagList.find(x => x.innerHTML === nodeHTML);
const foundNode = nodeList.find(x => x.data === nodeData);
run the following script when user select texts
let sel = window.getSelection();
let range = sel.getRangeAt(0);
let startNode = range.startContainer;
let endNode = range.endContainer;
if (startNode.nodeType == 3) {
var startIsText = true;
var startFlag = startNode.parentNode;
startNode = startNode.nodeValue;
} else {
var startIsText = false;
var startFlag = startNode;
}
if (endNode.nodeType == 3) {
var endIsText = true;
var endFlag = endNode.parentNode;
endNode = endNode.nodeValue;
} else {
var endIsText = false;
var endFlag = endNode;
}
let startOffset = range.startOffset;
let endOffset = range.endOffset;
let startTagName = startFlag.nodeName;
let startHTML = startFlag.innerHTML;
let endTagName = endFlag.nodeName;
let endHTML = endFlag.innerHTML;
//you can store this in database and use it
let rInfo = {
startNode: startNode,
startOffset: startOffset,
startIsText: startIsText,
startTagName: startTagName,
startHTML: startHTML,
endNode: endNode,
endOffset: endOffset,
endIsText: endIsText,
endTagName: endTagName,
endHTML: endHTML
};
window.localStorage.setItem("r", JSON.stringify(rInfo));
then use the following scripts when user go back to the page
function findEle(tagName, innerHTML) {
let list = document.getElementsByTagName(tagName);
for (let i = 0; i < list.length; i++) {
if (list[i].innerHTML == innerHTML) {
return list[i];
}
}
}
function show(startNode,startIsText,startOffset,
endNode,endIsText,endOffset,sP,eP) {
var s, e;
if (startIsText) {
let childs = sP.childNodes;
console.log(childs);
for (let i = 0; i < childs.length; i++) {
console.log(childs[i].nodeValue);
console.log(startNode);
if (childs[i].nodeType == 3 && childs[i].nodeValue == startNode)
s = childs[i];
console.log(s);
}
} else {
s = startNode;
}
if (endIsText) {
let childs = eP.childNodes;
console.log(childs);
for (let i = 0; i < childs.length; i++) {
if (childs[i].nodeType == 3 && childs[i].nodeValue == endNode)
e = childs[i];
console.log(e);
}
} else {
e = endNode;
}
let range = document.createRange();
range.setStart(s, startOffset);
range.setEnd(e, endOffset);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
function use(obj) {
let sP = findEle(obj.startTagName, obj.startHTML);
let eP = findEle(obj.endTagName, obj.endHTML);
show(
obj.startNode,
obj.startIsText,
obj.startOffset,
obj.endNode,
obj.endIsText,
obj.endOffset,
sP,
eP
);
}
let a = window.localStorage.getItem("r");
use(JSON.parse(a));

Get Text from Xpath and Highlight it

I am trying to build a E pub Reader. I am able to highlight the user selected text and i am getting the x path of that particular selected text. After that i am trying to build a function which takes x path as parameter and show the user selected text by changing background color. but its not working.
Code:-
function uiWebview_restoreSelection() {
var selectionDetails = "/HTML[1]/BODY[1]/DIV[1]/text()[1]|910|/HTML[1]/BODY[1]/DIV[1]/text()[1]|930";
//alert("selectionDetails"+selectionDetails);
if (selectionDetails != null) {
selectionDetails = selectionDetails.split(/\|/g);
alert("selectionDetails" + selectionDetails);
if (typeof window.getSelection != 'undefined') {
var selection = window.getSelection();
selection.removeAllRanges();
var range = document.createRange();
var selectionDetails0 = selectionDetails[0];
alert("selectionDetails0" + selectionDetails0);
selectionDetails0 = selectionDetails0.replace(/\//g, "/h:");
selectionDetails0 = selectionDetails0.replace("h:t", "t");
alert("selectionDetails0" + selectionDetails0);
var selectionDetails2 = selectionDetails[2];
alert("selectionDetails2" + selectionDetails2);
selectionDetails2 = selectionDetails2.replace(/\//g, "/h:");
selectionDetails2 = selectionDetails2.replace("h:t", "t");
alert("selectionDetails2" + selectionDetails2);
range.setStart(document.evaluate(selectionDetails0, document, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue, Number(selectionDetails[1]));
range.setEnd(document.evaluate(selectionDetails2, document, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue, Number(selectionDetails[3]));
document.designMode = "on";
var newSpanMark = document.createElement("span");
document.execCommand("HiliteColor", false, "red");
range.insertNode(newSpanMark);
document.designMode = "off";
}
}
}
Please suggest for the above problem.
Thanks in Advance

apply Highlight HTML text using javascript as in Microsoft word

I have the following code for highlighting html text using javascript:
var counter = 1;
function BindEventForHighlight() {
$('#ParaFontSize').bind("mouseup", HighlightText);
$('#ParaFontSize').unbind("mouseup", RemoveHighlight);
}
function UnBindHighlightEvent() {
$('#ParaFontSize').bind("mouseup", RemoveHighlight);
$('#ParaFontSize').unbind("mouseup", HighlightText);
}
function HighlightText() {
var text = window.getSelection();
var start = text.anchorOffset;
var end = text.focusOffset - text.anchorOffset;
range = window.getSelection().getRangeAt(0);
range1 = window.getSelection().toString();
var selectionContents = range.extractContents();
var span = document.createElement("span");
span.appendChild(selectionContents);
span.setAttribute("id", counter);
span.setAttribute("class", "highlight");
range.insertNode(span);
counter++;
}
function RemoveAllHighlights() {
var selection = document.getElementById('ParaFontSize');
var spans = selection.getElementsByTagName("span");
for (var i = 0; i < spans.length; i++) {
spans[i].className = "";
}
}
function RemoveHighlight() {
var selection = window.getSelection();
if (selection.toString() !== "" &&
selection.anchorNode.parentNode.nodeName === "SPAN") {
selection.anchorNode.parentNode.className = "";
}
else {
return false;
}
}
The HighlightText function uses range object to highlight text. and i want to save start and end of selected text into Data base, and when user get back to the same page he will see the highlighted text from previous time. also i want other scenarios as follow:
when the user highlight some text, he will be able to unhighlight all or part of this highlighted text and keep the remaining text highlighted.
the user able to clear all highlighted text in the page.
let's say i want this highlighter functions as the highlighter in MS word.
Thanks in advance
Really appreciated.

Categories

Resources