2015-01-29 3 views
1

XML 태그 및 속성을 자동 완성하려고합니다. 유효한 값은 서버에서 가져옵니다. 예를 들어,Ace 편집기에서 XML 값 및 속성 자동 완성

내가 같은 태그가있는 경우,

<status></status> 

내 커서가 열린 태그와 닫는 태그 안에, 내가 control + space를 치고 좋아하고있다 유효한 값은 드롭에 표시 만 것 하위. 예를 들면 : 내 커서가 따옴표 안에 초점을 맞출 경우 ok, error, warning는 ...

속성 마찬가지로

,

<status audience="">ok</status> 

나는 경우 드롭 다운에 표시에만 유효 관객을 싶습니다 타격 control + space.

여기까지 제가 지금까지 가지고 있습니다. 이 완성자는 내가 입력하는 단어를 완성합니다. 나는 내부에있는 태그의 종류와 해당 태그 또는 속성에 대한 특정 값을 보내는 방법을 아는 방법을 파악할 수 없습니다.

나를 가리키는 아이디어 나 예가 있습니까? 감사합니다./w

function loadEditor() { 
    var langTools = ace.require("ace/ext/language_tools"); 
    editor = ace.edit("editor"); 
    editor.setOptions({ 
     enableBasicAutocompletion: true, 
     enableLiveAutocompletion: true, 
     enableSnippets: true, 
    }); 
    editor.getSession().setMode("ace/mode/xml"); 

    var myCompleter = { 
     getCompletions: function(editor, session, pos, prefix, callback) { 
      if (prefix.length === 0) { 
       callback(null, []); 
       return; 
      }      
      $.getJSON("completions.php?a=completions&prefix=" 
        + prefix + "&content=" + session, function(json) { 
       callback(null, json.map(function(c) { 
        console.log("value: " + c.value); 
        return {value: c.value, caption: c.caption, meta: c.meta, score:c.score}; 
       })); 
      }) 
     } 
    }; 
    langTools.addCompleter(myCompleter); 
} 

답변

2

지금까지 XML 완료를 사용하여 프로젝트를 찾을 수 없었으므로 구현 한 것입니다.

XhtmlTagInterpreter에는 이 있으며 {completeType: "attribute", tagName: "feline", attributeName: "breed"} 형태의 JavaScript 개체를 반환합니다. 이 예에서는 속성이 <feline breed="" /> 인 자동 완성을 시도합니다.

해당 데이터를 서버에 적절한 breed 값으로 보냅니다. 이 서비스는 귀하가 구현할 수 있습니다. 예 : https://www.example.com/services/mock/autocompleter/attribute.json?tagName=feline&attributeName=breed

반환되는 JSON은 다음과 같습니다.

[ 
    {"score":"1000","meta":"cats","caption":"siamese","value":"siamese"}, 
    {"score":"1000","meta":"cats","caption":"burmese","value":"burmese"}, 
    {"score":"1000","meta":"cats","caption":"bengal","value":"bengal"} 
] 

다음은 작동하는 JavaScript입니다.

function XHtmlTagInterpreter(row, col, session) { 
    "use strict"; 
    this.row = row; 
    this.col = col; 
    this.session = session; 
    this.leftOfCursor = null; 
    this.rightOfCursor = null; 
    this.leftType = null; 
    this.rightType = null; 
} 

/** 
* Sets the left of cursor property used by other methods. This is a 
* string without new lines from the beginning of the document to the 
* letter just before the cursor. 
*/ 
XHtmlTagInterpreter.prototype.setLeftOfCursor = function() { 
    "use strict"; 
    this.leftOfCursor = ""; 
    for (var r=0; r<=this.row; r++) { 
     if (r === this.row) { 
      var line = this.session.getLine(r); 
      for (var c=0; c<this.col; c++) { 
       this.leftOfCursor += line[c]; 
      } 
     } else { 
      this.leftOfCursor += this.session.getLine(r); 
     } 
    } 
}; 

/** 
* Sets the right of cursor property used by other methods. This is a 
* string without new lines from the letter just to the right of the cursor 
* to the end of the document. 
*/ 
XHtmlTagInterpreter.prototype.setRightOfCursor = function() { 
    "use strict"; 
    this.rightOfCursor = ""; 
    for (var r=this.row; r<=this.session.getLength(); r++) { 
     if (r === this.row) { 
      var line = this.session.getLine(r); 
      for (var c=this.col; c<line.length; c++) { 
       this.rightOfCursor += line[c]; 
      } 
     } else { 
      this.rightOfCursor += this.session.getLine(r); 
     } 
    } 
}; 

/** 
* Sets the left type depending on first non-whitespace character to the 
* left of the cursor position. We look for a right angle or a quotation. 
* If a right angle we assume the cursor is inside a tag. If quotation the 
* cursor is inside an attribute. We set the left type value to 'value' 
* or 'attribute'. 
*/ 
XHtmlTagInterpreter.prototype.setLeftType = function() { 
    "use strict"; 
    this.setLeftOfCursor(); 
    if (this.leftOfCursor === undefined || this.leftOfCursor.length === 0) { 
     this.leftType = ""; 
     return; 
    } 
    for (var i=this.leftOfCursor.length-1; i>=0; i--) { 
     if (this.leftOfCursor[i] === " " || this.leftOfCursor[i] === "\t") { 
      continue; 
     } 
     if (this.leftOfCursor[i] === ">") { 
      this.leftType = "value"; 
      return; 
     } else if (this.leftOfCursor[i] === '"') { 
      this.leftType = "attribute"; 
      return; 
     } else { 
      this.leftType = ""; 
      return; 
     } 
    } 
}; 

/** 
* Sets the right type depending on first non-whitespace character to the 
* right of the cursor position. We look for a left angle or a quotation. 
* If a left angle we assume the cursor is inside a tag. If quotation the 
* cursor is inside an attribute. We set the right type value to 'value' 
* or 'attribute'. 
*/ 
XHtmlTagInterpreter.prototype.setRightType = function() { 
    "use strict"; 
    this.setRightOfCursor(); 
    if (this.rightOfCursor === undefined 
      || this.rightOfCursor.length === 0) { 
     this.rightType = ""; 
     return; 
    } 
    for (var i=0; i<this.rightOfCursor.length; i++) { 
     if (this.rightOfCursor[i] === " " 
       || this.rightOfCursor[i] === "\t") { 
      continue; 
     } 
     if (this.rightOfCursor[i] === "<") { 
      this.rightType = "value"; 
      return; 
     } else if (this.rightOfCursor[i] === '"') { 
      this.rightType = "attribute"; 
      return; 
     } else { 
      this.rightType = ""; 
      return; 
     } 
    } 
}; 

/** 
* Returns the tag name to be sent to autocompleter service. 
* @returns {[email protected];[email protected];[email protected];replace|String} 
*/ 
XHtmlTagInterpreter.prototype.getCompleteInfo = function() { 
    "use strict"; 
    this.setLeftType(); 
    this.setRightType(); 
    if (this.leftType !== this.rightType) { 
     return ""; 
    } 
    if (this.leftType === "value") { 
     var tagName = this.leftOfCursor.trim() 
       .replace(new RegExp("^.*<([a-z:]+).*?>$"), "$1"); 
     return {completeType: "value", tagName: tagName}; 
    } else if (this.leftType === "attribute") { 
     var tagName = this.leftOfCursor.trim() 
       .replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$1"); 
     var attributeName = this.leftOfCursor.trim() 
       .replace(new RegExp("^.*<([a-z:]+).*?([a-z:]+)\s*=\s*\"$"), "$2"); 
     return {completeType: "attribute", tagName: tagName, 
      attributeName: attributeName}; 
    } else { 
     return null; 
    } 
}; 

var loadEditor = function(editor) { 
    var chileCompleter = { 
     getCompletions: function(editor, session, pos, prefix, callback) { 
      if (prefix.length === 0) { 
       var line = session.getLine(pos.row); 
       if (undefined !== line) { 
        var interpreter = new XHtmlTagInterpreter(pos.row, 
         pos.column, session); 
        var completeInfo = interpreter.getCompleteInfo(); 
        if (undefined === completeInfo || completeInfo === null 
          || undefined === completeInfo.completeType 
          || completeInfo.completeType === null 
          || completeInfo.completeType.length === 0 
          || undefined === completeInfo.tagName 
          || completeInfo.tagName === null 
          || completeInfo.tagName.length === 0) { 
         callback(null, []); 
         return; 
        } 

        $.getJSON(chileContextPath 
          + "services/mock/autocompleter/" 
          + encodeURIComponent(completeInfo.completeType) 
          + ".json?tagName=" 
          + encodeURIComponent(completeInfo.tagName) 
          + "&attributeName=" 
          + encodeURIComponent(completeInfo.attributeName), 
          function(json) { 
         callback(null, json.content.map(function(c) { 
          return {value: c.value, caption: c.caption, 
           meta: c.meta, score:c.score}; 
         })); 
        }) 
       } 
      } else { 
       callback(null, []); 
       return; 
      } 
     } 
    }; 

    editor = ace.edit("chile-editor"); 
    editor.setOptions({ 
     enableBasicAutocompletion: [chileCompleter], 
     enableLiveAutocompletion: true, 
     enableSnippets: true, 
    }); 
    editor.setTheme("ace/theme/clouds"); 
    editor.getSession().setMode("ace/mode/xml"); 
    editor.getSession().setUseWrapMode(true); 
    editor = loadXKbml(editor); 

    return editor; 
};