如何将jQuery选择中的一组令牌范围转换为一组rangy范围?
例如我有这个:
<div class="test-input">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas
convallis dui id erat pellentesque et rhoncus nunc semper. Suspendisse
malesuada {hendrerit velit nec }tristique. Aliq{uam gravida mauris at
ligula venenatis rhoncus. Suspendisse inter}dum, nisi nec consectetur
pulvinar, lorem augue ornare felis, vel lacinia erat nibh in ve{lit.
</p>
<p>
Hendr}erit, felis ac fringilla lobortis, massa ligula aliquet justo, sit
amet tincidunt enim quam {sollicitudin} nisi. Maecenas ipsum augue,
commodo sit amet aliquet ut, laoreet ut nunc. Vestibulum ante ipsum
primis in {fauc}ibus orci luctus et ultrices posuere cubilia Curae;
Pellentesque tincidunt eros quis tellus laoreet ac dignissim turpis
luctus. Integer nunc est, {pulvinar ac tempor ac, pretium ut odio.
</p>
<p>
Pellentesque in arcu sit amet} odio scelerisque tincidunt. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas.
</p>
</div>
我希望将{
和}
之间的文本转换为范围(并删除令牌)。
我试过用这个:
function tokensToRanges(element) {
element = $(element);
var node = element.get(0);
var ranges = [];
do {
var text = $(node).text(),
start = text.indexOf('{'),
end = text.indexOf('}') - 1,
input = null;
input = node.innerHTML.replace('{', '').replace('}', '');
element.html(input);
var range = rangy.createRange();
range.selectCharacters(node, start, end);
ranges.push(range);
} while ($(node).text().indexOf('{') != -1);
return ranges;
}
但它的范围不正确。我认为selectCharacters
方法忽略了空格。
如果可能的话,我宁愿不使用TextRangeModule
。
答案 0 :(得分:1)
selectCharacters()
不会忽略所有空格,但会忽略折叠的空格。例如,如果文本节点包含三个连续的空格字符,则只有第一个空格字符有助于字符计数。我可以为该方法添加一个选项来关闭该行为。
在回答你的问题时,Rangy的测试套件的功能有点像你想要的,所以我在下面对它进行了改编。开始和结束范围标记可能出现在不同的节点中。
演示:http://jsfiddle.net/timdown/DdeFr/
代码:
function RangeInfo() {}
RangeInfo.prototype = {
setStart: function(node, offset) {
this.sc = node;
this.so = offset;
},
setEnd: function(node, offset) {
this.ec = node;
this.eo = offset;
},
toRange: function() {
var range = rangy.createRange();
range.setStart(this.sc, this.so);
range.setEnd(this.ec, this.eo);
return range;
}
};
function getTextNodesIn(node) {
var textNodes = [];
function getTextNodes(node) {
if (node.nodeType === 3) {
textNodes.push(node);
} else {
for (var i = 0, l = node.childNodes.length; i < l; i++) {
getTextNodes(node.childNodes[i]);
}
}
}
getTextNodes(node);
return textNodes;
}
function tokensToRanges(el) {
var rangeInfos = [];
var currentRangeInfo;
var textNodes = getTextNodesIn(el);
$.each(textNodes, function() {
var searchStartIndex = 0;
var searchIndex;
while ( (searchIndex = this.data.indexOf(currentRangeInfo ? "}" : "{", searchStartIndex)) != -1 ) {
// Remove the marker. Doing this breaks existing ranges
// in this node, which is why we use RangeInfo objects
// instead of ranges
this.data = this.data.slice(0, searchIndex) + this.data.slice(searchIndex + 1);
if (currentRangeInfo) {
currentRangeInfo.setEnd(this, searchIndex);
rangeInfos.push(currentRangeInfo);
currentRangeInfo = null;
} else {
currentRangeInfo = new RangeInfo();
currentRangeInfo.setStart(this, searchIndex);
}
searchStartIndex = searchIndex;
}
});
// Convert RangeInfos into ranges
var ranges = [];
$.each(rangeInfos, function() {
ranges.push(this.toRange());
});
return ranges;
}
var ranges = tokensToRanges(document.body);
var applier = rangy.createCssClassApplier("highlight");
applier.applyToRanges(ranges);