web-dev-qa-db-ja.com

JavaScript構文がACEの変更ハンドラーで有効かどうかを判別します

インタラクティブなJavaScript編集に [〜#〜] ace [〜#〜] エディターを使用しています。エディターをJavaScriptモードに設定すると、ACEはコードが有効かどうかを自動的に判断し、有効でない場合はエラーメッセージと行番号を強調表示します。

changeイベントハンドラーの実行中に、eval()を試みる前に、ACEがコードが有効であると見なすかどうかを検出したいと思います。私がそれをするかもしれないと私が思った唯一の方法は:

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

しかしながら:

  1. 特定のクラスのUIに要素が存在することに頼るのは非常に壊れやすいように見えますが、さらに重要なのは、
  2. 解析の視覚的な更新は、afterchangeコールバックが発生した後に発生します。

したがって、実際には500ミリ秒以上待つ必要があります(JavaScriptワーカーが起動するまでの遅延)。

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

JSモード用の文書化されていないAPIに、エラーがあるかどうかを尋ねるより良い方法はありますか?

24
Phrogz

アノテーションが変更されると、現在のセッションが発生しますonChangeAnnotationイベント。

その後、新しいセットのアノテーションを次のように取得できます。

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

トリックをするようです。 row askeyと配列asvalueを持つJSONオブジェクトを返しますvalue配列には、各行に複数の注釈があるかどうかに応じて、複数のオブジェクトが含まれる場合があります。

構造は次のとおりです(firebugからコピー–私が作成したテストスクリプト用)

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

...

});

そう..

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

注釈が変更されたときに、現在のエース編集セッションのすべての注釈のリストが表示されます。

お役に立てれば!

26
hkrish

DOMをトラバースするよりもおそらく速い解決策を見つけました。エディタのセッションには、使用できるgetAnnotationsメソッドがあります。各注釈には、エラーかどうかを示すタイプがあります。

これが、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);
        }
    }
}

私の知る限り、注釈には他に2つのタイプがあります。「警告」と「情報」です。これらも確認したい場合に備えて。

多くの場合、コードにはエラーがありますが、アノテーションのリストにはないため、グローバルで(コールバック関数の範囲外で)機能した以前のコードを追跡しました。その場合、エラーのあるコードを評価するとき、それはコードであり、代わりに古いコードを評価します。

2つの評価は遅くなるように見えますが、これまでのところ、パフォーマンスはそれほど悪くないように思えます。

3
AndrewKS

Ace1.1.7でワーカーイベントをサブスクライブできることがわかりました。

Javascriptコードの場合、「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();
    });
  }
});

JSONコードの場合、「error」および「ok」イベントをサブスクライブします。

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

Aceは内部でJsHintを使用し( worker )、ファイルで確認できるように、次のイベントが発行されます。

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

このイベントに subscribe するか、必要に応じてJSHintコードを自分で呼び出すことができます(かなり短いです)。

2
Jan Jongboom