修改选择,选择单词,然后重新连接插入位置

时间:2016-05-22 08:37:31

标签: javascript selection wysiwyg

所以我试图在javascript中创建一个所见即所得的编辑器。我试图做的是:当我没有做出选择并且只有一个单词的插入符号时,我想选择单词,在其上执行命令然后将插入符号移回其位置。 / p>

实施例: 在我执行代码之前(插入符号应该在我的函数之后):

将这个词改为b | old

后:

将这个词设为粗体 |

jsFiddle示例:jsFiddle

到目前为止我的代码:

    if (window.getSelection && (sel = window.getSelection()).modify) {
        doc.focus(); // the editor
        var range = sel.getRangeAt(0);
        var oldRange = document.createRange();
        oldRange.setStart(range.startContainer, range.startOffset);
        oldRange.setEnd(range.endContainer, range.endOffset);

        sel.collapseToStart();           

        sel.modify("move", "forward", "character");
        sel.modify("move", "backward", "word");
        sel.modify("extend", "forward", "word");

        document.execCommand(command, false, value);

        // Restore selection, Dosen't work as I expected
        sel.removeAllRanges();
        sel.addRange(oldRange);
}

2 个答案:

答案 0 :(得分:2)

问题在于,运行ldconfig后,它会立即重置范围,您可以在document.execCommand上执行console.log并注释掉oldRange行以进行确认。保存旧范围的唯一方法是序列化它,就像我在下面的示例中所做的那样。看看

解决方案

document.execCommand
changeStyle = function(command) {
    var sel;  
    var doc = document.getElementById('editor');

    if (window.getSelection && (sel = window.getSelection()).modify) {
      doc.focus();
      var range = sel.getRangeAt(0);
      var oldRange = saveCaret(doc);
    
      sel.collapseToStart();
    
      sel.modify("move", "forward", "character");
      sel.modify("move", "backward", "word");
      sel.modify("extend", "forward", "word");
    
      document.execCommand(command, false, null);
    
      // Restore selection, well, it isn't restoring it
      restoreCaret(doc, oldRange)
    }
}
saveCaret = function(container) {
  var range = window.getSelection().getRangeAt(0);
  var preSelectionRange = range.cloneRange();
  preSelectionRange.selectNodeContents(container);
  preSelectionRange.setEnd(range.startContainer, range.startOffset);
  var start = preSelectionRange.toString().length;

  return {
    start: start,
    end: start + range.toString().length
  };
};
restoreCaret = function(container, position) {
  var charIndex = 0, range = document.createRange();
  range.setStart(container, 0);
  range.collapse(true);
  var nodeStack = [container], node, foundStart = false, stop = false;

  while (!stop && (node = nodeStack.pop())) {
    if (node.nodeType == 3) {
      var nextCharIndex = charIndex + node.length;
      if (!foundStart && position.start >= charIndex && position.start <= nextCharIndex) {
        range.setStart(node, position.start - charIndex);
        foundStart = true;
      }
      if (foundStart && position.end >= charIndex && position.end <= nextCharIndex) {
        range.setEnd(node, position.end - charIndex);
        stop = true;
      }
      charIndex = nextCharIndex;
    } else {
      var i = node.childNodes.length;
      while (i--) {
        nodeStack.push(node.childNodes[i]);
      }
    }
  }

  var sel = window.getSelection();
  sel.removeAllRanges();
  sel.addRange(range);
}

答案 1 :(得分:1)

对于将来可能会偶然发现此问题的任何人,实现起来并不是那么简单-主要是由于跟踪和操纵插入符号的困难。另外,跨浏览器的行尾也是任何尝试实现的问题的原因。

但是,jquery.caret在启用插入符号信息和操纵方面做得很好,因此请考虑将其检出。