While working with the ACE Editor, I noticed a terrifying feature. They call it "undo".
OK so maybe it's not that terrifying, but it does have a terrifying behavior—it undos back beyond when a new project is started. That is, it undos back to when the editor was empty. So, hitting multiple Ctrl-Z's will eventually land you, not on the original version of the project, but on a blank page. Since I am auto-saving my work in localStorage, I very quickly have a blank project with no obvious means to restore my work.
That's frustrating for me, but would be horrifying for a kid working through Gaming JavaScript.
I do not see any obvious way to remove an entry from ACE's UndoManager. I do see that EditSession has a
setUnderManager() method—perhaps I can use that to initialize the undo at the point just after the editor is updated with setValue().So I do just that:
var ace = ace.edit("editor");
ace.setTheme("ace/theme/chrome");
ace.getSession().setMode("ace/mode/javascript");
ace.getSession().setUseWrapMode(true);
ace.getSession().setUseSoftTabs(true);
ace.setPrintMarginColumn(false);
ace.setDisplayIndentGuides(false);
ace.setFontSize('18px');
var emacs = require("ace/keyboard/emacs").handler;
ace.setKeyboardHandler(emacs);
ace.setValue((documents.length > 0) ? documents[ 0 ].code : templates[ 0 ].code, -1);
ace.getSession().setUndoManager(new UndoManager());I will have to do the same anywhere else that setValue() changes the contents (or generalize a code editor setValue function). But first, I need to make sure this works.It does not. In the JavaScript console, I see:
Uncaught ReferenceError: UndoManager is not definedAh, it seems that I will have to require.js it into my current namespace. I try:
var UndoManager = require("ace/ace").UndoManager;But that does not work. It seems that UndoManager is not a property of the ACE constructor.The
define() statement for UndoManager is:define('ace/undomanager', /* ... */);This suggests that the following might work:var UndoManager = require("ace/undomanager");
editor.getSession().setUndoManager(new UndoManager());However, I still seem to lack a constructor:Uncaught TypeError: object is not a functionIf I check this out in the JavaScript console, it seems that I need the
UndoManger property of that require object:And indeed, the following does the trick:
// ...
ace.setValue(/* ... */);
var UndoManager = require("ace/undomanager").UndoManager;
ace.getSession().setUndoManager(new UndoManager());Not only so the page load without error, but undo works as desired. I can type a bunch of junk in my current project, Ctrl-Z to my heart's content, but never move back to the blank page before the first setValue().I believe that removes any objection that I might have had to replacing CodeMirror with ACE. They both seem very similar—both in features and quality. The only real difference is that I had to implement a very hacky fix to a CodeMirror+Chrome paint issue. Any issues that I have had with ACE, I have been able to resolve via the API. I do think that I will take some time tomorrow to see if I can get JavaScript syntax checking working under ACE when mixing HTML and JavaScript. That would be very nice.
Day #537



Hello! Thank you for you post. It helped me to solve the same problem.
ReplyDeleteBut i found a much more easy solution:
var undo_manager = ace.getSession().getUndoManager();
undo_manager.reset();
ace.getSession().setUndoManager(undo_manager);