Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using xpath to restore a DOM range in JavaScript

I'm trying to grasp the best approach to saving (serializing) and restoring (deserializing) a DOM selection or range. There is a post here on stringifying a range object, but it frankly doesn't really work.

The situation is an interactive text book using the Webkit view of Adobe Air. I have static (built-in) html content that the user can highlight and bookmark (annotate). This mechanism all works, but I need to be able to store and restore these annotations. I would rather not store a modified version of the DOM, but rather use the static version then reapply the users annotations that I am storing in a SQLite DB along with other needed metadata. DOM manipulation is pretty new for me, and so far my attempts to serialize a DOM::range have failed. What I realized though is that I really seem to only need the start and end containers and the start and end offsets. Then I can recreate the range with document.createRange().

What I could use guidance on is the best approach to serializing the start and end containers. My first thought was xpath, but so far my attempts have come up short. Looking at the Mozilla docs for DOM::Range seems pretty straight forward, but creating a reliable xpath to restore a range isn't quite clicking for me.

like image 604
Pelted Avatar asked Apr 24 '26 19:04

Pelted


1 Answers

HTML

<div>
    <div id="container" style="background-color: red;">
        <p id="paraText">Text</p>
    </div>
</div>

JavaScript

function serialize(node) {
    if (typeof XMLSerializer != "undefined") {  // Firefox, etc.
        return (new XMLSerializer()).serializeToString(node);
    }
    else if (node.xml) {  // IE
        return node.xml;
    }
};

function parseXMLString(xml) {
    if (typeof DOMParser != "undefined") {  // Firefox, etc.
       var dp = new DOMParser();
       return dp.parseFromString(xml, "application/xml");
    }
    else if (typeof ActiveXObject != "undefined") {  // IE
        var doc = XML.newDocument();
        doc.loadXML(xml);
        return doc;
    }
};

var contextNode = document.getElementById('container');
var xmlString = serialize(contextNode);
var doc = parseXMLString(xmlString);

// Get elements from document using XPath
var xpathResult = doc.evaluate('//.', doc.firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

// Insert elements back into document (I used replace in order to show that the document is actually changed)
contextNode.parentNode.replaceChild(xpathResult.singleNodeValue.firstChild, contextNode);
like image 87
clarkb86 Avatar answered Apr 27 '26 11:04

clarkb86



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!