I'm using the ACE editor for interactive JavaScript editing. When I set the editor to JavaScript mode, ACE automatically determines if the code is valid or not, with an error message and line number highlighted when it's not.
During the change
event handler, I want to detect if ACE thinks the code is valid or not before I attempt to eval()
it. The only way I thought that I might do it is:
var jsMode = require("ace/mode/javascript").Mode; var editor = ace.edit('mycode'), edEl = document.querySelector('#mycode'); editor.getSession().setMode(new jsMode); editor.getSession().on('change',function(){ // bail out if ACE thinks there's an error if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return; try{ eval(editor.getSession().getValue()); }catch(e){} });
However:
change
callback occurs.Thus, I actually have to wait more than 500ms (the delay before the JavaScript worker kicks in):
editor.getSession().on('change',function(){ setTimeout(function(){ // bail out if ACE thinks there's an error if (edEl.querySelector('div.ace_gutter-cell.ace_error')) return; try{ eval(editor.getSession().getValue()); }catch(e){} },550); // Must be longer than timeout delay in javascript_worker.js });
Is there a better way, something in an undocumented API for the JS mode, to ask whether there are any errors or not?
The current session fires onChangeAnnotation event when annotations change.
after that the new set of annotations can be retrieved as follows
var annotations = editor.getSession().getAnnotations();
seems to do the trick. It returns a JSON object which has the row as key and an array as value. The value array may have more than one object, depending on whether there are more than one annotation for each row.
the structure is as follows (copied from firebug –for a test script that I wrote)
// annotations would look like ({ 82:[ {/*annotation*/ row:82, column:22, text:"Use the array literal notation [].", type:"warning", lint:{/*raw output from jslint*/} } ], rownumber : [ {anotation1}, {annotation2} ], ... });
so..
editor.getSession().on("changeAnnotation", function(){ var annot = editor.getSession().getAnnotations(); for (var key in annot){ if (annot.hasOwnProperty(key)) console.log("[" + annot[key][0].row + " , " + annot[key][0].column + "] - \t" + annot[key][0].text); } }); // thanks http://stackoverflow.com/a/684692/1405348 for annot.hasOwnProperty(key) :)
should give you a list of all annotations in the current Ace edit session, when the annotations change!
Hope this helps!
I found a solution that is probably faster than traversing the DOM. The editor's session has a getAnnotations method you can use. Each annotation has a type that shows whether they are an error or not.
Here is how I set my callback for the on 'change'
function callback() { var annotation_lists = window.aceEditor.getSession().getAnnotations(); var has_error = false; // Unfortunately, you get back a list of lists. However, the first list is // always length one (but not always index 0) go_through: for (var l in annotation_lists) { for (var a in annotation_lists[l]) { var annotation = annotation_lists[l][a]; console.log(annotation.type); if (annotation.type === "error") { has_error = true; break go_through; } } } if (!has_error) { try { eval(yourCodeFromTextBox); prevCode = yourCodeFromTextBox; } catch (error) { eval(prevCode); } } }
As far as I know, there are two other types for annotations: "warning" and "info", just in case you'd like to check for those as well.
I kept track of the pervious code that worked in a global (well, outside the scope of the callback function) because often there would be errors in the code but not in the list of annotations. In that case, when eval'ing the errored code, it would be code and eval the older code instead.
Although it seems like two evals would be slower, it seems to me like the performance is no that bad, thus far.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With