可通过标签进行可编辑的环绕元素;无法使光标移出新近选择的内容

时间:2018-12-30 22:34:38

标签: javascript jquery html css

我在我的学校项目网站上有一个div,它被用作用户友好的文本编辑器。但是,如果我在编辑器中选择了所有文本,并尝试用<code> tags </code>包围它,则无法使光标离开它,它会继续将我键入的任何内容添加到同一标签<code>

一段时间后,我放弃了它,但是后来我找到了this的答案,并试图修改那里提到的jsfiddle,以期使其起作用。但没有运气。

如果我可以说,选择任意一行中的最后一个单词并用<code>标记将其包围,那么我可以将光标移出没有非环绕文本的位置,但是最后没有要跳转到的纯文本格式,因此光标停留在<code>

如何确保光标不会卡在添加的标签中? 也许是将光标移出的一种方法?

jsFiddle

function surroundSelection() {
    var code = document.createElement("code");
    code.style.fontStyle = "italic";
    code.style.color = "#333";
    code.style.background = "#ddd";
    
    if (window.getSelection) {
        var sel = window.getSelection();
        if (sel.rangeCount) {
            var range = sel.getRangeAt(0).cloneRange();
            range.surroundContents(code);
            sel.removeAllRanges();
            sel.addRange(range);
        }
    }
}
div, input {
  padding:10px; 
  
}

div {border:1px solid;}
<input type="button" onclick="surroundSelection()" value="Surround">
<div contenteditable="true">One two three four</div>

2 个答案:

答案 0 :(得分:1)

这里有一个古怪的解决方法。不再使用环绕声,而是将内容复制到新节点中。然后,我们在末尾添加一个空格。现在,即使选择了所有文本,也可以在代码块之后单击。

编辑:添加了sel.collapseToEnd();根据评论(谢谢)。通过直接将用户置于正常的键入上下文中,它改善了体验。但是,仍然需要该空间,没有它就无法工作。

编辑:现在在开始和结束处添加空间。

编辑:删除用于发送到服务器的间隔符。

let rowHeight = 50
let rowIndexToSnapTo = 20
grid.setContentOffset(CGPoint(x: 0, y: rowHeight * rowIndexToSnapTo))
function surroundSelection() {
  let code = document.createElement("code");
  code.style.fontStyle = "italic";
  code.style.color = "#333";
  code.style.background = "#ddd";
  const newSpan = () => {
    let span = document.createElement('span');
    span.classList.add('codespacer');
    span.innerHTML = '&nbsp;';
    return span;
  }

  if (window.getSelection) {
    let sel = window.getSelection();
    if (sel.rangeCount) {
      let range = sel.getRangeAt(0).cloneRange();
      code.innerHTML = range.toString();
      range.deleteContents();
      range.insertNode(newSpan());
      range.insertNode(code);
      range.insertNode(newSpan());
      sel.removeAllRanges();
      sel.addRange(range);
      sel.collapseToEnd();
    }
  }
}


function getContentForSave() {
  let codeSection = document.querySelector('#codeSection');
  // Copy into a temporary element (otherwise the text will change in the UI)
  let tempSection = document.createElement('div');
  tempSection.innerHTML = codeSection.innerHTML;
  console.log(`Before: ${tempSection.innerHTML}`);
  
  // Remove all codespacers 
  let spacers = tempSection.querySelectorAll('.codespacer');
  for(let space of spacers) {
    tempSection.removeChild(space);
  }
  console.log(`After: ${tempSection.innerHTML}`);
  
  return tempSection.innerHTML;
}
div,
input {
  padding: 10px;
}

div {
  border: 1px solid;
}

答案 1 :(得分:1)

我认为您可以克服的一种方法是在代码后附加一个空白textNode,然后将光标移到其位置。这样,用户可以立即继续编写普通文本。

以下是细分:

  • 使用document.createTextNode('\u00A0')创建一个包含空格字符的textNode。请注意,文字' '在我的浏览器(Chrome 70)上无法使用。
  • 将新的空白文本节点添加到div
  • 使用range将新的空文本节点添加到当前range.setEnd()中,以便我们可以使用selection.collapseToEnd()方法将光标移到末尾。

一起(fiddle

+ function addPad() {
+   var $input = document.querySelector('div');
+   var pad = document.createTextNode('\u00A0');
+   $input.appendChild(pad);
+   return pad;
+ }

  function surroundSelection() {
    var sel = window.getSelection();
    if (!sel || !sel.rangeCount) return;

    var code = document.createElement("code");  
    var range = sel.getRangeAt(0).cloneRange();
    range.surroundContents(code);
    sel.removeAllRanges();
    sel.addRange(range);

+   // create empty node + add it to div
+   var padNode = addPad();

+   // update the current range to include the empty node.
+   // since we only add 1 space, the `offset` is set to 1.
+   range.setEnd(padNode, 1);

+   // move the cursor to very end of range
+   sel.collapseToEnd();
  }