I am using the highlighter module in Rangy.
I have a div
element, which has some html. The html is actually loaded from a file using ajax, I have a button which does this loading.
Once the text is loaded, I can select a portion of the displayed html and press my "Highlight" button. This calls some Rangy code and highlights the text as desired...
//called on document load
rangy.init();
cssApplier = rangy.createCssClassApplier(highlightClassName, { normalize: true });
highlighter = rangy.createHighlighter(document, "TextRange");
highlighter.addClassApplier(cssApplier);
//called on "Highlight" button click
highlighter.highlightSelection(highlightClassName, selection);
For the purpose of replicating, please select a large portion for first highlight.
Next, I click my load html button to reload the html. The highlight is gone, as expected. But now I select another bit of text, which happens to overlap the first highlight that I did. Now when I press the "Highlight" button, for some reason the highlight is the one from the previous highlight. Why is this happening?
I know there must be something to do with the merging, but I can't understand why. When I debug the JS I can see that the selection (from rangy.getSelection()
) is what I expect it to be.
Here is a JSFiddle replication of the problem
The reason this is happening is because each highlight exists as a pair of character offsets rather than having references to actual ranges in the DOM, meaning that when some part of the DOM is replaced, existing highlights remain blissfully unaware and continue to assume they are applied to the original character range.
Your workaround is fine. Another way would be to call the highlighter's removeHighlights()
method:
highlighter.removeHighlights(highlighter.highlights);
Demo: http://jsfiddle.net/8pMEt/1/
I'm going to add a removeAllHighlights()
method that will do the same thing.
One thing that the documentation doesn't make clear is that highlighting is designed to work on static DOMs, or at least DOMs with text content that doesn't change. Changing the DOM after highlights have been created could obviously throw character offsets off and the whole thing falls down.
I solved this problem by re-creating the highlighter prior to each highlightSelection
call. I don't know why this works, but the highlighter must store some data regarding previous highlights that is uses for highlight merging or something.
The code in my question can be changed as follows to solve the problem:
//called on document load
rangy.init();
cssApplier = rangy.createCssClassApplier(highlightClassName, { normalize: true });
//called on "Highlight" button click
highlighter = rangy.createHighlighter(document, "TextRange");
highlighter.addClassApplier(cssApplier);
highlighter.highlightSelection(highlightClassName, selection);