2012-02-29 19 views
23

Estoy usando el editor ACE para la edición de JavaScript interactiva. Cuando configuro el editor en modo JavaScript, ACE determina automáticamente si el código es válido o no, con un mensaje de error y un número de línea resaltados cuando no lo es.Determine si la sintaxis de JavaScript es válida en el controlador de cambio de ACE

Durante el controlador de eventos change, quiero detectar si ACE cree que el código es válido o no antes de intentar eval(). La única manera que pensé que podría hacerlo es:

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){} 
}); 

Sin embargo:

  1. Apoyado en la presencia de un elemento de la interfaz de usuario con una clase particular, parece muy frágil, pero lo más importante,
  2. La actualización visual para el análisis ocurre después de se produce la devolución de llamada change.

lo tanto, que en realidad tienen que esperar más de 500 ms (el retardo antes de que el trabajador JavaScript entra en acción):

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 
}); 

¿Hay una mejor manera, algo en una API no documentada para el modo de JS, para preguntar si hay algún error o no?

+0

realmente no sé mucho acerca de la ECA, pero que podría explicar por qué está utilizando eval? – hradac

+0

@hradac Mejor que eso, [te mostraré] (http://phrogz.net/JS/d3-playground/) el trabajo (en progreso). – Phrogz

+0

Estoy haciendo algo similar y espero una respuesta también. La evaluación es demasiado costosa para ejecutarla todo el tiempo. – AndrewKS

Respuesta

2

Ace utiliza JsHint internamente (en un worker) y como se puede ver en el archivo hay un evento emitido:

this.sender.emit("jslint", lint.errors); 

Puede subscribe a este evento, o llamar al código JSHint mismo (que es bastante corto) cuando sea necesario.

+1

Suscribirse al evento parece una buena idea, por lo que no lo analizo dos veces para cada edición, y también porque 'require (" ../ narcissus/jsparse ")' devuelve 'null' para mí. ¿Alguna idea sobre qué objeto se emite esa sesión? ¿El editor? ¿La sesión? Si edita su respuesta con un código que muestre cómo suscribirse, definitivamente ganará la aceptación. :) – Phrogz

+0

¿Alguna sugerencia sobre qué registrarse? – Phrogz

3

Encontré una solución que es probablemente más rápida que atravesar el DOM. La sesión del editor tiene un método getAnnotations que puede usar. Cada anotación tiene un tipo que muestra si son un error o no.

Así es como puedo configurar mi devolución de llamada para el de 'cambio'

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); 
     } 
    } 
} 

Por lo que yo sé, hay otros dos tipos de anotaciones: "advertencia" y "info", en caso de que Me gustaría verificar también esos.

Realicé un seguimiento del código anterior que funcionaba en un global (bueno, fuera del alcance de la función de devolución de llamada) porque a menudo habría errores en el código pero no en la lista de anotaciones. En ese caso, al evaluar el código con error, sería el código y evaluar el código anterior en su lugar.

Aunque parece que dos evaluaciones serían más lentas, me parece que el rendimiento no es tan malo, hasta ahora.

25

La sesión actual se activa en Cambio de anotación evento cuando cambian las anotaciones.

después de que el nuevo conjunto de anotaciones se pueden recuperar de la siguiente manera

var annotations = editor.getSession().getAnnotations(); 

parece hacer el truco.Devuelve un objeto JSON que tiene la fila como clave y una matriz como valor. La matriz de valor puede tener más de un objeto, dependiendo de si hay más de una anotación para cada fila.

la estructura es la siguiente (copiado de Firebug -por un script de prueba que escribí)

// 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} ], 

... 

}); 

así ..

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) :) 

debería darle una lista de todas las anotaciones en el actual ¡Sesión de edición de As, cuando las anotaciones cambian!

Espero que esto ayude!

+0

Esta es una buena información, pero no ayuda a detectar el problema de inmediato: las anotaciones (incluidos los errores) no están disponibles en la devolución de llamada 'change' para el editor; tienes que esperar hasta que se produzca la validación asincrónica. – Phrogz

+0

Editado la respuesta! Espero que ayude ahora! – hkrish

+0

El formato getAnnotaciones() ha cambiado ... ahora es una matriz de objetos. – DrFriedParts

2

He encontrado que puede suscribirse eventos trabajador en Ace 1.1.7:

Para código javascript, suscríbase evento 'JSLint':

session.setMode('ace/mode/javascript}'); 
session.on('changeMode', function() { 
    if (session.$worker) { 
    session.$worker.on('jslint', function(lint) { 
     var messages = lint.data, types; 
     if (!messages.length) return ok(); 
     types = messages.map(function(item) { 
     return item.type; 
     }); 
     types.indexOf('error') !== -1 ? ko() : ok(); 
    }); 
    } 
}); 

Para el código JSON, suscríbase 'error' y 'OK "evento:

session.setMode('ace/mode/json'); 
session.on('changeMode', function() { 

    // session.$worker is available when 'changeMode' event triggered 
    // You could subscribe worker events here, whatever changes to the 
    // content will trigger 'error' or 'ok' events. 

    session.$worker.on('error', ko); 
    session.$worker.on('ok', ok); 
}); 
Cuestiones relacionadas