Ace 在 Firefox 的焦点上选择编辑器中的所有文本

Ace selects all text in editor on focus in Firefox

我在 Bootstrap 3 模式中嵌入了一个 Ace 编辑器。在显示模式之前,我在编辑器中这样设置值:

var editor = ace.edit(aceEditorId);
editor.session.setValue(val, -1); // set value at document start
editor.session.selection.clearSelection();

我还有一个 "shown" 模态事件处理程序来调整编辑器的大小:

$(editSnippetSelector).on("shown.bs.modal", function () {
        var editorId = getSnippetEditorId();
        var snippetEditor = ace.edit(editorId);
        snippetEditor.resize();

当我在 Firefox 中关注编辑器时,所有编辑器文本都被选中。我无法通过单击移动光标或删除选择。我只能通过按退格键或其他键(例如字母或回车)来擦除文本。

这不会发生在 Chrome 或 IE 中。

作为实验,我也加了这段代码也无济于事:

codeEditor.on("focus", function () {
    codeEditor.getSession().setValue(codeEditor.getSession().getValue());
    codeEditor.clearSelection();
});

我还应该看哪里?还有其他人看到过类似的行为吗?

更新:

我注意到 ace.js 中有一个 onSelect 函数在无限循环中被调用。它在第 2061 行:https://github.com/ajaxorg/ace-builds/blob/master/src-noconflict/ace.js#L2061

函数代码如下:

var onSelect = function(e) {
    if (copied) {
        copied = false;
    } else if (isAllSelected(text)) {
        host.selectAll();
        resetSelection();
    } else if (inputHandler) {
        resetSelection(host.selection.isEmpty());
    }
};

遍历 Firefox 调试器中的代码显示对 isAllSelected(text) returns 的调用为真,因此再次引发了选择事件。

这很可能是由于渲染器中的缓存大小过时所致。 您需要在模态显示后调用 editor.resize()

ace.js 有一个 onSelect 处理程序,它在 Firefox 中被无限循环调用。

这是该函数的原始代码:

var onSelect = function(e) {
    if (copied) {
        copied = false;
    } else if (isAllSelected(text)) {
        host.selectAll();
        resetSelection();
    } else if (inputHandler) {
        resetSelection(host.selection.isEmpty());
    }
};

text 是一个文本区域 DOM 元素。 isAllSelected(text) 检查是否所有文本都使用此代码 selected:

    return text.selectionStart === 0 && text.selectionEnd === text.value.length;

如您所见,returns 即使对于空文本区域也是如此,这会导致调用 host.selectAll() 以某种方式向下传播并再次触发 select 事件。

我添加了一个空文本区域检查,它解决了这个问题。现在的代码是这样的:

var onSelect = function(e) {
    if (copied) {
        copied = false;
    } else if (text.value && isAllSelected(text)) {
        host.selectAll();
        resetSelection();
    } else if (inputHandler) {
        resetSelection(host.selection.isEmpty());
    }
};