单行Ace编辑器

时间:2015-08-31 15:54:17

标签: javascript ace-editor

我试图设置只有一行文字的Ace编辑器。

这个想法是模仿<input type="text">框的行为,但是使用语法着色: enter image description here

目前,如果用户在编辑器中按下Enter,则会创建一个新行: enter image description here

所以我的问题是:

如何设置Ace以仅允许一行,如标准文本输入框?

以下是我迄今为止所尝试的内容,以及它未能成功的原因。

  • 如果editor.undo()

    ,请致电change e.lines.length > 1

    问题是,change在之前触发了,在增量中应用了实际的更改,因此undo()在这里不起作用(或者它涉及到以前的三角洲)

  • 如果keypress

    ,则取消Event.which = 13

    它有点工作但非常脏,并且它不能处理粘贴多行文本的情况,所以我们也需要处理paste事件 - 这将使这个解决方案甚至更脏。我也非常有信心会考虑更多边缘案例。

  • 尝试&#34;清空&#34; e

    中的on("change", function(e) { ... })

    例如,在回调函数中说e = {},前提是e只是对实际对象的引用。没有任何影响。

  • 尝试在Ace编辑器中找到内置参数来执行此操作

    尚未成功找到这样的参数......

4 个答案:

答案 0 :(得分:12)

您可以使用以下代码使编辑器的行为类似于输入类型=&#34; text&#34; (主要取自https://github.com/ajaxorg/ace/blob/v1.2.0/demo/kitchen-sink/layout.js#L103

&#13;
&#13;
var el = document.getElementById("textbox")
var editor = ace.edit(el);
editor.setOptions({
    maxLines: 1, // make it 1 line
    autoScrollEditorIntoView: true,
    highlightActiveLine: false,
    printMargin: false,
    showGutter: false,
    mode: "ace/mode/javascript",
    theme: "ace/theme/tomorrow_night_eighties"
});
// remove newlines in pasted text
editor.on("paste", function(e) {
    e.text = e.text.replace(/[\r\n]+/g, " ");
});
// make mouse position clipping nicer
editor.renderer.screenToTextCoordinates = function(x, y) {
    var pos = this.pixelToScreenCoordinates(x, y);
    return this.session.screenToDocumentPosition(
        Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
        Math.max(pos.column, 0)
    );
};
// disable Enter Shift-Enter keys
editor.commands.bindKey("Enter|Shift-Enter", "null")
&#13;
#textbox {
    font-size: 30px;
    border:solid 2px gray;
}
body{
   background: #161619;
   padding: 40px 20px
}
&#13;
<script src="https://ajaxorg.github.io/ace-builds/src/ace.js"></script>


<div id=textbox>var a = 1</div>
&#13;
&#13;
&#13;

答案 1 :(得分:6)

由于某些原因,e.preventDefaulte.stopPropagation都不适用于更改事件处理程序。但你可以做find-replace。

请参阅小提琴:http://jsfiddle.net/vittore/3rLfdtxb/

 var editor = ace.edit("editor");
 editor.setTheme("ace/theme/monokai");
 editor.getSession().setMode("ace/mode/javascript");
 editor.setFontSize(30)
 editor.getSession().on('change', function(e) {
    console.log(e)
    if (e.data.text.charCodeAt(0) === 10 && e.data.action == "insertText") {
      console.log('cancel event')
      //e.preventDefault() // doesnt work
      //e.stopPropagation()  // doesnt work
      editor.find(String.fromCharCode(10))
      editor.replaceAll(''); // this work
    }
 })

您甚至可以从处理程序中删除if语句,并在任何更改时替换换行符。

当你在变化中找到 - 替换时,你会从光标到所选行的末尾。在使用之后取消选择:

editor.selection.clearSelection()

答案 2 :(得分:0)

这两个现有答案对我来说都很有帮助,但是我仍然遇到一些必须解决的问题(某些原因显然是由于api的更改)。这是对我有用的两个答案的组合。

注意,例如,当您运行这些代码片段或jsFiddle时,CORS检查将阻止工作程序加载,只是因为示例“工作”并不意味着它在工作时将全部工作集成到您的项目中。

还请注意...这是使用钩子的React代码,但应使用基本代码。

它也使用来自Set width of ace editor instance according to the length of characters in it

的大小调整代码
const editDiv = useRef<HTMLDivElement>(null);

useEffect(() => {
    if (editing) {
      if (!editor && editDiv.current) {
        editDiv.current.textContent = value;
        const ed = ace.edit(editDiv.current);
        ed.setOptions({
          maxLines: 1,
          autoScrollEditorIntoView: true,
          highlightActiveLine: false,
          printMargin: false,
          showGutter: false,
          enableLiveAutocompletion: true,
          enableBasicAutocompletion: true,
          enableSnippets: false,
          mode: "ace/mode/javascript",
          theme: "ace/theme/tomorrow_night_eighties"
        });
        ed.commands.bindKey(
          "Up|Ctrl-P|Down|Ctrl-N|PageUp|PageDown",
          "null"
        );
        ed.commands.addCommand({
          name: "SaveOnEnter",
          bindKey: {
            win: "Enter",
            mac: "Enter",
            sender: "editor|cli"
          },
          exec: () => {
            setValue(ed.getValue());
            // Handle new value;
          }
        });
        ed.on("paste", e => {
          e.text = e.text.replace(/[\r\n]+/g, " ");
        });
        setEditor(ed);

        ed.getSession().on("change", e => {
          if (e.action == "insert" && ed.session.getValue().includes("\n")) {
            setTimeout(() => {
              // doing a replaceAll during a change event causes issues in the
              // worker, so we'll queue up the change
              ed.find(String.fromCharCode(10));
              ed.replaceAll("");
              ed.selection.clearSelection();
            }, 0);
          }
        });
        ed.renderer.on("beforeRender", (e, renderer) => {
          const rSession = renderer.session;
          const text = rSession.getLine(0);
          const charCount = rSession.$getStringScreenWidth(text)[0];
          const width =
            Math.max(charCount, 2) * renderer.characterWidth + // text size
            2 * renderer.$padding + // padding
            2 + // little extra for the cursor
            0; // add border width if needed

          renderer.container.style.width = width + "px";
          renderer.onResize(false, 0, width, renderer.$size.height);
        });
        ed.setWrapBehavioursEnabled(false);
        ed.session.setUseWrapMode(false);
        ed.focus();
      }
    } else {
      if (editor) {
        editor.renderer.on("beforeRender", () => {});
        editor.destroy();
        setEditor(undefined);
      }
    }
  }, [editing]);

  return <div ref={editDiv} style={{ width: "1em", height: "1.2em" }} />;

答案 3 :(得分:0)

尝试在maxLines属性中提供设置为{{1}的1。 我使用setOptionsreact-ace。 我将此作为可选/可配置的行为使用,在包装器组件上具有暴露的属性: 9.2.0