在 CodeMirror Textarea 的插入符号处插入文本

Insert Text at Caret on CodeMirror Textarea

我正在开发一个 Python 编辑器,我想添加一个功能来在 CodeMirror 文本区域的插入符位置插入文本。

有系列图片可以点击。单击一个时,该图片的 alt 属性将被保存,然后当您在文本区域内再次单击时,它会被复制到您的鼠标位置(演示 fiddle:https://jsfiddle.net/t0k7yp7n/1/

这是文本插入部分的脚本:

selected = '';

$('.insert').click(function() {
    console.log($(this).attr('alt'));
    selected = $(this).attr('alt');
});

$('#textbox').click(function() {
    insertAtCaret('textbox', selected)
        // Clear the selection so it isn't copied repeatedly
    selected = '';
});

function insertAtCaret(areaId, text) {
    var txtarea = document.getElementById(areaId);
    var scrollPos = txtarea.scrollTop;
    var strPos = 0;
    var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
        "ff" : (document.selection ? "ie" : false));
    if (br == "ie") {
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart('character', -txtarea.value.length);
        strPos = range.text.length;
    } else if (br == "ff") strPos = txtarea.selectionStart;

    var front = (txtarea.value).substring(0, strPos);
    var back = (txtarea.value).substring(strPos, txtarea.value.length);
    txtarea.value = front + text + back;
    strPos = strPos + text.length;
    if (br == "ie") {
        txtarea.focus();
        var range = document.selection.createRange();
        range.moveStart('character', -txtarea.value.length);
        range.moveStart('character', strPos);
        range.moveEnd('character', 0);
        range.select();
    } else if (br == "ff") {
        txtarea.selectionStart = strPos;
        txtarea.selectionEnd = strPos;
        txtarea.focus();
    }
    txtarea.scrollTop = scrollPos;
}

这是 CodeMirror 文本区域部分:

var editor;

//<![CDATA[
window.onload = function() {
    editor = CodeMirror.fromTextArea(document.getElementById('textbox'), {
      mode: {
        name: "python",
        version: 2,
        singleLineStringErrors: false
      },
      lineNumbers: true,
      indentUnit: 4
    });
  } //]]>
<!DOCTYPE html>
<html>

<head>

  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js" type="text/javascript"></script>
  <script src="http://www.skulpt.org/static/skulpt.min.js" type="text/javascript"></script>
  <script src="http://www.skulpt.org/static/skulpt-stdlib.js" type="text/javascript"></script>
  <script src="https://www.cs.princeton.edu/~dp6/CodeMirror/lib/codemirror.js" type="text/javascript"></script>
  <script src="https://www.cs.princeton.edu/~dp6/CodeMirror/mode/python/python.js" type="text/javascript"></script>
  <script src="skulpt-codemirror.js" type="text/javascript"></script>
  <script src="load-save-py.js" type="text/javascript"></script>
  <script src="insert.js" type="text/javascript"></script>
  <link href="https://www.cs.princeton.edu/~dp6/CodeMirror/lib/codemirror.css" rel="stylesheet" type="text/css">
  <title>Python Editor</title>
</head>

<body>
  Filename:
  <input id="inputFileNameToSaveAs">
  <button onclick="saveTextAsFile()">Save</button>
  <br>
  <input type="file" id="fileToLoad">
  <button onclick="loadFileAsText()">Open</button>
  <br>
  <br>
  <a href="#!">
    <img class="insert" alt="#1">
    <img class="insert" alt="#2">
    <img class="insert" alt="#3">
  </a>
  <br>
  <br>
  <textarea id="textbox" name="textbox"></textarea>
  <br>
  <button onclick="runit()" type="button">Run</button>
  <pre id="dynamicframe"></pre>
  <div id="canvas"></div>
</body>

</html>

但是,当我将它们放在一个文件中时,当我单击图片时,它们的 alt 不会复制到文本区域。为什么会这样,我该如何解决?

使用 CodeMirror 时,您的 <textarea /> 将在视觉上被 CodeMirror 提供的编辑器替换,并且与您的 <textarea /> 相关的大部分代码将无法按原样使用。

后台发生的事情是,您的实际 <textarea /> 将首先标记为样式 display: none;。不显示,<textarea /> 上绑定的事件不会实际触发。然后,CodeMirror 实际上会在 DOM 中添加他自己的代码,以在您现在未显示的 <textarea /> 位置显示一个新的编辑器。

例如,新初始化的 CodeMirror 编辑器的 HTML 代码中写入了字符串 'Hello World',它看起来像:

<div class="CodeMirror-lines">
    <div style="position: relative; outline: none;">
        <div class="CodeMirror-measure">
            <div style="width: 50px; height: 50px; overflow-x: scroll;"></div>
        </div>
        <div class="CodeMirror-measure"></div>
        <div style="position: relative; z-index: 1;"></div>
        <div class="CodeMirror-cursors">
            <div class="CodeMirror-cursor" style="left: 74px; top: 0px; height: 13px;">&nbsp;</div>
        </div>
        <div class="CodeMirror-code">
            <div style="position: relative;">
                <div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;">
                    <div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">1</div>
                </div><pre><span style="padding-right: 0.1px;"><span class="cm-variable">Hello</span> <span class="cm-variable">World</span></span></pre></div>
        </div>
    </div>
</div>

您的 <textarea /> 已不再使用。

CodeMirror 本身提供了一个编程API,可以用来做你想做的事。基本上,所需的步骤是:

  • 检查编辑器何时获得焦点。
  • 聚焦时,检查图片是否已被单击,以及 selected 文本是否可用(图像的 alt)。
  • 如果是,则在当前位置插入selected文字(图片的alt)。

与这些步骤关联的 JavaScript 代码如下所示:

// Listen to the editor focus events.
editor.on('focus', function () {
  // Only insert if a value has been previously selected.
  if (selected.length > 0) {
    // Fetch the current CodeMirror document.
    var doc = editor.getDoc();

    // Insert the text at the cursor position.
    doc.replaceSelection(selected);

    // Clear the selection so it isn't copied repeatedly.
    selected = '';
  }
});

您可以在 this JSFiddle 上查看工作示例。

简而言之,此代码将用文本替换代码镜像当前选择(或当前光标位置,当没有任何选择时):

codemirror.doc.replaceSelection('text to replace');