xml-hint.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. (function() {
  2. "use strict";
  3. var Pos = CodeMirror.Pos;
  4. function getHints(cm, options) {
  5. var tags = options && options.schemaInfo;
  6. var quote = (options && options.quoteChar) || '"';
  7. if (!tags) return;
  8. var cur = cm.getCursor(), token = cm.getTokenAt(cur);
  9. var inner = CodeMirror.innerMode(cm.getMode(), token.state);
  10. if (inner.mode.name != "xml") return;
  11. var result = [], replaceToken = false, prefix;
  12. var isTag = token.string.charAt(0) == "<";
  13. if (!inner.state.tagName || isTag) { // Tag completion
  14. if (isTag) {
  15. prefix = token.string.slice(1);
  16. replaceToken = true;
  17. }
  18. var cx = inner.state.context, curTag = cx && tags[cx.tagName];
  19. var childList = cx ? curTag && curTag.children : tags["!top"];
  20. if (childList) {
  21. for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].indexOf(prefix) == 0)
  22. result.push("<" + childList[i]);
  23. } else {
  24. for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.indexOf(prefix) == 0))
  25. result.push("<" + name);
  26. }
  27. if (cx && (!prefix || ("/" + cx.tagName).indexOf(prefix) == 0))
  28. result.push("</" + cx.tagName + ">");
  29. } else {
  30. // Attribute completion
  31. var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
  32. if (!attrs) return;
  33. if (token.type == "string" || token.string == "=") { // A value
  34. var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)),
  35. Pos(cur.line, token.type == "string" ? token.start : token.end));
  36. var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues;
  37. if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return;
  38. if (token.type == "string") {
  39. prefix = token.string;
  40. if (/['"]/.test(token.string.charAt(0))) {
  41. quote = token.string.charAt(0);
  42. prefix = token.string.slice(1);
  43. }
  44. replaceToken = true;
  45. }
  46. for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].indexOf(prefix) == 0)
  47. result.push(quote + atValues[i] + quote);
  48. } else { // An attribute name
  49. if (token.type == "attribute") {
  50. prefix = token.string;
  51. replaceToken = true;
  52. }
  53. for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.indexOf(prefix) == 0))
  54. result.push(attr);
  55. }
  56. }
  57. return {
  58. list: result,
  59. from: replaceToken ? Pos(cur.line, token.start) : cur,
  60. to: replaceToken ? Pos(cur.line, token.end) : cur
  61. };
  62. }
  63. CodeMirror.xmlHint = getHints; // deprecated
  64. CodeMirror.registerHelper("hint", "xml", getHints);
  65. })();