ReadViewSDK/Sources/RDReaderView/EPUBCore/Resources/rangy-serializer.js

94 lines
3.0 KiB
JavaScript

(function() {
if (!window.rangy) {
window.rangy = {};
}
if (window.rangy.serializeRange && window.rangy.deserializeRange) {
return;
}
function normalizeHref(rawHref) {
if (!rawHref) { return ''; }
var value = String(rawHref);
value = value.replace(/^.*?:\/\/[^/]+\//, '');
value = value.split('#')[0];
value = value.replace(/^\/+/, '');
try {
value = decodeURIComponent(value);
} catch (error) {
}
return value;
}
function nodePath(node) {
var path = [];
var current = node;
while (current && current !== current.ownerDocument) {
var parent = current.parentNode;
if (!parent) { break; }
var index = Array.prototype.indexOf.call(parent.childNodes, current);
path.unshift(index);
current = parent;
}
return path;
}
function nodeFromPath(doc, path) {
var current = doc;
for (var index = 0; index < path.length; index += 1) {
if (!current || !current.childNodes || current.childNodes.length <= path[index]) {
return null;
}
current = current.childNodes[path[index]];
}
return current;
}
function documentContexts(rootDoc) {
var items = [];
if (!rootDoc) { return items; }
items.push(rootDoc);
var frames = rootDoc.querySelectorAll ? rootDoc.querySelectorAll('iframe') : [];
Array.prototype.forEach.call(frames, function(frame) {
try {
if (!frame.contentDocument) { return; }
documentContexts(frame.contentDocument).forEach(function(item) {
items.push(item);
});
} catch (error) {
}
});
return items;
}
window.rangy.serializeRange = function(range, doc) {
var ownerDocument = doc || (range && range.startContainer && range.startContainer.ownerDocument) || document;
return JSON.stringify({
kind: 'dom-range',
documentHref: normalizeHref(ownerDocument.location && ownerDocument.location.href),
startPath: nodePath(range.startContainer),
startOffset: range.startOffset,
endPath: nodePath(range.endContainer),
endOffset: range.endOffset
});
};
window.rangy.deserializeRange = function(rangeInfo, rootDoc) {
try {
var payload = typeof rangeInfo === 'string' ? JSON.parse(rangeInfo) : rangeInfo;
var documentHref = normalizeHref(payload.documentHref);
var resolvedDocument = (documentContexts(rootDoc || document).find(function(candidate) {
return normalizeHref(candidate.location && candidate.location.href) === documentHref;
})) || (rootDoc || document);
var startNode = nodeFromPath(resolvedDocument, payload.startPath || []);
var endNode = nodeFromPath(resolvedDocument, payload.endPath || []);
if (!startNode || !endNode) { return null; }
var range = resolvedDocument.createRange();
range.setStart(startNode, payload.startOffset || 0);
range.setEnd(endNode, payload.endOffset || 0);
return range;
} catch (error) {
return null;
}
};
})();