我正试图从用户选择的文本中删除前导或尾随(有时两者都有)空白。根据这个答案执行。这适用于简单的情况,但是,当所选文本包含标记或
时,它会失败。
示例:在小提琴中,尝试从右到左高亮显示-- hi this is bob.
,包括末端的空格,然后按Trim。
这导致:
Uncaught IndexSizeError: Failed to execute 'setEnd' on 'Range': The offset 24 is larger than or equal to the node's length (5).
我想可以捕捉到这一点
if (method == range.setEnd && range.startOffset + ind >= range.endContainer.length)
但我不知道该怎么处理。我也试着用替换硬盘空间
e2 = document.getElementById('e2');
e2.innerHTML = e2.innerHTML.replace(/ /gi, ' ');
但是,这会使选择为空。代码:
function removeWsFromSelection(fromStart) {
selection = window.getSelection();
range = selection.getRangeAt(0);
if (fromStart) {
regex = /[^s]/;
container = range.startContainer;
method = range.setStart;
} else {
regex = /s+$/;
container = range.endContainer;
method = range.setEnd;
}
match = regex.exec(selection.toString());
if (match) {
ind = match.index;
if (ind > 0) {
// ind is the first non-ws char from the start or first ws char from the end,
// hence (startOffset + ind)
method.call(range, container, range.startOffset + ind);
rng = range.cloneRange();
selection.removeAllRanges();
selection.addRange(rng);
}
}
}
顺便说一句,不幸的是,Selection.modify
不适合我,而且它被认为是非标准的。
如果您对范围修改很满意,您可以检查从开始到结束的修剪符号的长度,然后修改范围的startOffset和endOffset。但对于startContainer和endContainer不是同一节点的情况,这肯定不是一个银弹。至少它适用于某些情况。
const sel = window.getSelection();
const text = sel.toString();
const range = sel.getRangeAt(0);
const startOffset = text.length - text.trimStart().length;
const endOffset = text.length - text.trimEnd().length;
if (startOffset) {
range.setStart(range.startContainer, range.startOffset + startOffset);
}
if (endOffset) {
range.setEnd(range.endContainer, range.endOffset - endOffset);
}
这很难看,不能处理一般情况,但似乎有效:
function removeWsFromSelection(fromStart) {
selection = window.getSelection();
range = selection.getRangeAt(0);
if (fromStart) {
regex = /[^s]/;
container = range.startContainer;
method = range.setStart;
}
else {
regex = /s+$/;
container = range.endContainer;
method = range.setEnd;
}
match = regex.exec(selection.toString());
if (match) {
ind = match.index;
if (ind > 0) {
// ind is the first non-ws char from the start or first ws char from the end,
// hence (startOffset + ind)
if (method == range.setEnd && range.startOffset + ind >= range.endContainer.length) {
match = regex.exec(range.endContainer.textContent);
if (match) {
range.setEnd(range.endContainer, match.index);
}
}
else {
method.call(range, container, range.startOffset + ind);
}
rng = range.cloneRange();
selection.removeAllRanges();
selection.addRange(rng);
}
}
}
我修改了Micheal的答案,使其能够处理多个范围和跨节点边界的范围。这似乎在我所有的测试中都能始终如一地减少选择,但我确信总有边缘情况的空间。
TypeScript,但很容易适应普通JS。
export function trimRanges(selection: Selection) {
for (let i = 0, range = selection.getRangeAt(0); i < selection.rangeCount; range = selection.getRangeAt(i++)) {
const text = selection.toString();
const startOffset = text.length - text.trimStart().length;
const endOffset = text.length - text.trimEnd().length;
if (startOffset) {
const offset = range.startOffset + startOffset;
if (offset < 0) {
// If the range will underflow the current element, then it belongs in the previous element
const start = range.startContainer.parentElement.previousSibling;
range.setStart(start, start.textContent.length + offset);
} else if (offset > range.startContainer.textContent.length) {
// If the range will overflow the current element, then it belongs in the next element
const start = range.startContainer.parentElement.nextSibling;
range.setStart(start, offset - range.startContainer.textContent.length);
} else {
range.setStart(range.startContainer, offset);
}
}
if (endOffset) {
const offset = range.endOffset - endOffset;
if (offset < 0) {
// If the range will underflow the current element, then it belongs in the previous element
const end = range.endContainer.parentElement.previousSibling;
range.setEnd(end, end.textContent.length + offset);
} else if (offset > range.endContainer.textContent.length) {
// If the range will overflow the current element, then it belongs in the next element
const end = range.endContainer.parentElement.nextSibling;
range.setEnd(end, offset - range.endContainer.textContent.length);
} else {
range.setEnd(range.endContainer, offset);
}
}
}
}
请注意,这确实会修改附加到所选内容的范围。如果你需要原子性,你可以假设在编辑之前克隆每个范围,删除所有范围,然后将克隆的范围添加回选择中,但我没有发现这种方法有任何问题。