问题
I am writing a Chrome extension and I need to pass in the value that the user has selected on the website to my server. I am using the code window.getSelection() which returns a range object. I am using JSON to pass the range object back to my server but it is not working. I am new to this, but I think the problem lies with the fact that you can only pass in text with JSON, and the range object includes both the DOM structure (which is not text) and the actual text selection (which is text). Am I correct? Is there an alternative?
var selection = window.getSelection();
$.getJSON(url, {data:selection}, function(moot) {
alert("done");
});
回答1:
A simple workaround is not to serialize and send the entire select object, but rather to store the start and end points as XPaths (along with their offsets). Something like this would do:
function makeXPath (node, currentPath) {
/* this should suffice in HTML documents for selectable nodes, XML with namespaces needs more code */
currentPath = currentPath || '';
switch (node.nodeType) {
case 3:
case 4:
return makeXPath(node.parentNode, 'text()[' + (document.evaluate('preceding-sibling::text()', node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength + 1) + ']');
case 1:
return makeXPath(node.parentNode, node.nodeName + '[' + (document.evaluate('preceding-sibling::' + node.nodeName, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength + 1) + ']' + (currentPath ? '/' + currentPath : ''));
case 9:
return '/' + currentPath;
default:
return '';
}
}
function restoreSelection () {
var selection = window.getSelection();
selection.removeAllRanges();
var range = document.createRange();
range.setStart(document.evaluate(selectionDetails[0], document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue, Number(selectionDetails[1]));
range.setEnd(document.evaluate(selectionDetails[2], document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue, Number(selectionDetails[3]));
selection.addRange(range);
}
}
function getSelection() {
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var selectObj = {
'startXPath': makeXPath(range.startContainer),
'startOffset': range.startOffset,
'endXPath': makeXPath(range.endContainer),
'endOffset': range.endOffset
}
return selectObj
}
Not thoroughly tested, but the general idea is here.
Sources: This and That
回答2:
If you need to send the user selections in your page
var selection = window.getSelection();
for(i=0;i<selection.rangeCount;i++)
a[i]=selection.getRangeAt(i);
$.getJSON(url, {data:a.toString()}, function(moot) {
alert("done");
});
Note: instead of toString()
, you can use join('<separator>')
as well based on your need
Using window.getSelection().toString()
would combine all selections without separator
回答3:
Have you tried window.getSelection().toString()
? That should get just the text value by itself.
MDN is currently down, but you might want to check out the DOMSelection documentation there: https://developer.mozilla.org/En/DOM/Selection
EDIT
You could also try using the anchorNode and focusNode properties to grab the nodes in which the selection starts and stops. If you really need the raw html, you could do something like focusNode.parentNode.outerHTML to get the whole block (it looks like you can't do outerHTML on the focus or anchorNodes directly).
ie:
var selection = window.getSelection();
var payload = {
selectedText: selection.toString(),
startHTML: selection.anchorNode.parentNode.outerHTML,
endHTML: selection.focusNode.parentNode.outerHTML
}
and then parse it on the other side. You could also peel out other information from the nodes so that you don't have to pass the whole html strings over the wire.
来源:https://stackoverflow.com/questions/9074091/range-object-with-json