94 lines
3.0 KiB
JavaScript
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;
|
|
}
|
|
};
|
|
})();
|