epubjs
Version:
Render ePub documents in the browser, across many devices
125 lines (98 loc) • 3.14 kB
JavaScript
var OReader = OReader || {};
OReader.Stitcher = {};
OReader.Stitcher.parsePart = function(partString) {
var tokens = partString.split("["); // Split string into element and other
var attributes = {};
var part = {
"string" : partString,
"attributes" : attributes,
"node" : tokens[0],
"offset" : 1
};
var attrString;
var re = /\@([^=]+)=[\'\"]([^\'^\"]+)[\'\"]/g;
var match;
// Part muight have additional information such as id or offset
if(tokens[1]){
// remove the last part
attrString = tokens[1].replace(']', '');
// If there is an offset it will be numerical
if(!isNaN(parseFloat(attrString)) && isFinite(attrString)){ // is a number
part.offset = parseInt(attrString);
} else {
// Run through string looking for @key=value paris
do {
match = re.exec(attrString);
if (match) {
// Add pairs to attributes object
attributes[match[1]] = match[2];
}
} while (match);
}
}
return part;
};
OReader.Stitcher.parseXpath = function(_xpath){
// Split path into parts
var parts = _xpath.substring(1).split("/");
var xpath = [];
// Parse each part and add to xpath array
parts.forEach(function(part){
var parsed = OReader.Stitcher.parsePart(part);
xpath.push(parsed);
});
return xpath;
};
OReader.Stitcher.createElement = function(part, _doc){
var doc = _doc || document;
var element = doc.createElement(part.node);
for (var attribute in part.attributes){
if (part.attributes.hasOwnProperty(attribute)) {
element.setAttribute(attribute, part.attributes[attribute]);
}
}
return element;
};
OReader.Stitcher.rebuild = function(_xpath, doc, payload){
var xpath = OReader.Stitcher.parseXpath(_xpath);
var walked = [];
var prevElement = doc.documentElement;
var wrapper;
var last = xpath.pop();
var wrapperPresent = doc.evaluate(_xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if(!wrapperPresent){
// Create the terminal element
wrapper = OReader.Stitcher.createElement(last, doc);
// wrap the current payload in element
while (payload.childNodes.length > 0) {
if(payload.childNodes[0] != prevElement){
wrapper.appendChild(payload.childNodes[0]);
}
}
} else {
// All elements in xpath already present in correct location
return;
}
// Process xpath parts
xpath.forEach(function(part){
var present;
var element;
walked.push(part.string);
// Check if part is present in DOM
present = doc.evaluate("//"+walked.join('/'), doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
// console.log(present, walked.join('/'))
if(!present) {
// Create the element, add attributes
element = OReader.Stitcher.createElement(part, doc);
// Add to previously created element
prevElement.appendChild(element);
// Continue
prevElement = element;
} else {
// Continue
prevElement = present;
}
});
// Add the wrapper last
prevElement.appendChild(wrapper);
};