简体   繁体   中英

Ace Editor (javascript): Triggering a tab press event for Ace Editors event handlers (not just inserting '/t' or spaces)

I am using Ace Editor to build a code replay program. I store all the keys pressed when you type code, and then I replay them in Ace Editor. I have finished storing and replaying all keyboard/mouse input, but am having issues replaying tab presses.

Ace Editor handles tabs within a textarea DOM. The default behavior for a textarea when tab is pressed is to move to the next DOM, so I know they are using preventDefault() and using their own handler in order to allow softTab (insertion of 1,2,3, or 4 spaces before all highlighted text).

My goal is to cause Ace editor to trigger the tab event - such that whatever is currently highlighted in the Ace editor is tabbed over the correct number of spaces. Does anyone know how to do this?

Here are a list of options I've tried and why they don't work:

  1. Store tab presses on keydown and then calculate the column value and insert the spaces in that location. BUT - this fails when you have some text half highlighted. The correct functionality should shift the entire word over, but this would just insert spaces in the middle of the word.
  2. Store the location and keys pressed whenever editor.on('change', some_event_handler) fires, which gives me exactly what was input and the location (perfect for replay) except it doesnt tell me whether tab or spacebar was pressed (it will fire for both and spacebar is already handled). Plus this still inserts spaces at the location (potentially in middle of a word instead of shifting word over) as in number 1.

For example:

editor.getSession().on('change', function(e) {
    if (handlers) {
        var text = e.data.text;
        if (text == ' ' || text == '  ' || text == '   ' || text == '    ') {
           //FAILS because it doesn't know if its space or a single space tab.
  1. Try to trick Ace Editor to trigger a tab by storing '/t' and inserting it into the ace Editor.

For example (storage code):

function keypress_handler(e) {
    var key = e.which;
    var text = String.fromCharCode(key);
    switch(key) {
        case 9: //Tab
            text = '\t'; // manually add tab
            //Code to store this event for replay later
            break;        
    }

For example (replay code):

// Assuming the cursor/selection is in the correct position
editor.insert(log.text);

At this point, I was beginning to think about building tab from scratch (when to shift multiple things if multiple lines are selected, how far to shift, how to handle if a word is half highlighted when tab is pressed), but Ace clearly already does this when tab is pressed, so I would like to just trigger the tab press. Normally to trigger a tab press, I'd simply do:

// trigger an artificial Tab Keydown event for Ace Editor using jQuery
var tab_press= $.Event('keydown');
tab_press = 9; // Tab keycode
$('.editor').trigger(tab_press);

But this causes results in no behavior. Any suggestions?

In Ace all of the user input from keyboard is processed via commands. This is used in Ace to record and replay macros see https://github.com/ajaxorg/ace/blob/v1.1.4/lib/ace/commands/command_manager.js#L52-L96 .

If you want to record user input and then to replay it you can use

// record
commands=[]
editor.commands.on("afterExec", function(e) {
   commands.push({name: e.command.name, args: e.args})
});

// replay
commands.forEach(function(e) {editor.execCommand(e.name, e.args)})

Capturing mouse input is a bit tricker, but from question it seems you already know how to do it.

This pull request is somewhat related to your question. It allows to emulate user input by calling simulateKeys("a", "b", "ctrl-Left", "Tab")

I read through the source code here:

https://github.com/ajaxorg/ace/blob/master/lib/ace/commands/default_commands.js

And found the following snippet of code:

{
    name: "indent",
    bindKey: bindKey("Tab", "Tab"),
    exec: function(editor) { editor.indent(); },
    multiSelectAction: "forEach",
    scrollIntoView: "selectionPart"
}

Thus, to trigger a tab (that works in all cases), simply call:

editor.indent();

How incredibly simple - wish there was some documentation out there for this so that many hours could have been spared.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM