I am using the highlighter module of rangy to highlight a certain portion of the HTML page. A specific div is going to be using the module only which is actually an angular directive. I am persisting the highlight range in the backend and rendering it again when the page gets loaded again. This is because I want to persist the highlights. The problem I am facing is that the page has few dynamic components which may or may not change on every page load. This creates problems in rendering the saved highlights. To resolve this, I tried to use the static element while creating the highlighter, using the following code
var highlighter = rangy.createHighlighter(element);
This gave me the following error -
TypeError: Failed to execute 'setStart' on 'Range': parameter 1 is not of type 'Node'.
at WrappedRange.api.createCoreModule.rangeProto.setStart (allPluginJsPartTwo.js:42934)
at WrappedRange.moveToBookmark (allPluginJsPartTwo.js:42427)
at Object.characterRangeToRange (allPluginJsPartTwo.js:45712)
at Highlight.getRange (allPluginJsPartTwo.js:45816)
at Highlight.apply (allPluginJsPartTwo.js:45837)
at Highlighter.deserialize (allPluginJsPartTwo.js:46203)
at allCommonJs.js:11098
at processQueue (allFrameworkJs.js:14804)
at allFrameworkJs.js:14820
at Scope.$eval (allFrameworkJs.js:16064)
(Please ignore the JS file names and code lines. They are merged by grunt.)
The error comes, because a particular containerNode is undefined. The containerNode which is basically missing from here is defined as element.body which is undefined for any DOM element except document element.
I tried using the following silly workaround.
element.body = document.body;
which was just doing the exact same stuff as sending document object in createHighlighter().
So I am assuming that the rangy.createHighlighter()
needs to have only document object as the parameter. My question is, how can I make it work for any element, not just the document object?
The exact requirement is not supported by Rangy
, however, I had to create a separate function which was not that complex and I was not sure why it was not inbuilt with Rangy
.
But anyway, here's how I did it. Rangy
uses character ranges to serialize and deserialize the highlighted content. So I normalized the ranges before saving them till the div which contained my concerned static HTML.
For example, if the div had an id of page-container
, I got the character range till that and subtracted that part from the range of the highlight before saving and when I wanted to deserialise the highlight, I just calculated the offset again and added it back to the normalized range and it worked like magic :-D
Here's the code which calculated the offset -
function getRangeOffset(){
var converter = highlighter.converter;
var pageContainer = document.getElementById('page-container');
var containerRange = rangy.createRange(document);
containerRange.setStart(pageContainer,0);
var containerCharRange = converter.rangeToCharacterRange(containerRange);
var rangeOffset = containerCharRange.start;
return parseInt(rangeOffset);
}