dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/xml.js
branchdew
changeset 544 08ffdc3938e7
parent 460 c0f1788183dd
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/xml.js	Wed Jan 23 13:18:46 2013 +0100
     1.3 @@ -0,0 +1,324 @@
     1.4 +CodeMirror.defineMode("xml", function(config, parserConfig) {
     1.5 +  var indentUnit = config.indentUnit;
     1.6 +  var Kludges = parserConfig.htmlMode ? {
     1.7 +    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
     1.8 +                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
     1.9 +                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
    1.10 +                      'track': true, 'wbr': true},
    1.11 +    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
    1.12 +                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
    1.13 +                       'th': true, 'tr': true},
    1.14 +    contextGrabbers: {
    1.15 +      'dd': {'dd': true, 'dt': true},
    1.16 +      'dt': {'dd': true, 'dt': true},
    1.17 +      'li': {'li': true},
    1.18 +      'option': {'option': true, 'optgroup': true},
    1.19 +      'optgroup': {'optgroup': true},
    1.20 +      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
    1.21 +            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
    1.22 +            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
    1.23 +            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
    1.24 +            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
    1.25 +      'rp': {'rp': true, 'rt': true},
    1.26 +      'rt': {'rp': true, 'rt': true},
    1.27 +      'tbody': {'tbody': true, 'tfoot': true},
    1.28 +      'td': {'td': true, 'th': true},
    1.29 +      'tfoot': {'tbody': true},
    1.30 +      'th': {'td': true, 'th': true},
    1.31 +      'thead': {'tbody': true, 'tfoot': true},
    1.32 +      'tr': {'tr': true}
    1.33 +    },
    1.34 +    doNotIndent: {"pre": true},
    1.35 +    allowUnquoted: true,
    1.36 +    allowMissing: true
    1.37 +  } : {
    1.38 +    autoSelfClosers: {},
    1.39 +    implicitlyClosed: {},
    1.40 +    contextGrabbers: {},
    1.41 +    doNotIndent: {},
    1.42 +    allowUnquoted: false,
    1.43 +    allowMissing: false
    1.44 +  };
    1.45 +  var alignCDATA = parserConfig.alignCDATA;
    1.46 +
    1.47 +  // Return variables for tokenizers
    1.48 +  var tagName, type;
    1.49 +
    1.50 +  function inText(stream, state) {
    1.51 +    function chain(parser) {
    1.52 +      state.tokenize = parser;
    1.53 +      return parser(stream, state);
    1.54 +    }
    1.55 +
    1.56 +    var ch = stream.next();
    1.57 +    if (ch == "<") {
    1.58 +      if (stream.eat("!")) {
    1.59 +        if (stream.eat("[")) {
    1.60 +          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
    1.61 +          else return null;
    1.62 +        }
    1.63 +        else if (stream.match("--")) return chain(inBlock("comment", "-->"));
    1.64 +        else if (stream.match("DOCTYPE", true, true)) {
    1.65 +          stream.eatWhile(/[\w\._\-]/);
    1.66 +          return chain(doctype(1));
    1.67 +        }
    1.68 +        else return null;
    1.69 +      }
    1.70 +      else if (stream.eat("?")) {
    1.71 +        stream.eatWhile(/[\w\._\-]/);
    1.72 +        state.tokenize = inBlock("meta", "?>");
    1.73 +        return "meta";
    1.74 +      }
    1.75 +      else {
    1.76 +        var isClose = stream.eat("/");
    1.77 +        tagName = "";
    1.78 +        var c;
    1.79 +        while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
    1.80 +        if (!tagName) return "error";
    1.81 +        type = isClose ? "closeTag" : "openTag";
    1.82 +        state.tokenize = inTag;
    1.83 +        return "tag";
    1.84 +      }
    1.85 +    }
    1.86 +    else if (ch == "&") {
    1.87 +      var ok;
    1.88 +      if (stream.eat("#")) {
    1.89 +        if (stream.eat("x")) {
    1.90 +          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");          
    1.91 +        } else {
    1.92 +          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
    1.93 +        }
    1.94 +      } else {
    1.95 +        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
    1.96 +      }
    1.97 +      return ok ? "atom" : "error";
    1.98 +    }
    1.99 +    else {
   1.100 +      stream.eatWhile(/[^&<]/);
   1.101 +      return null;
   1.102 +    }
   1.103 +  }
   1.104 +
   1.105 +  function inTag(stream, state) {
   1.106 +    var ch = stream.next();
   1.107 +    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
   1.108 +      state.tokenize = inText;
   1.109 +      type = ch == ">" ? "endTag" : "selfcloseTag";
   1.110 +      return "tag";
   1.111 +    }
   1.112 +    else if (ch == "=") {
   1.113 +      type = "equals";
   1.114 +      return null;
   1.115 +    }
   1.116 +    else if (/[\'\"]/.test(ch)) {
   1.117 +      state.tokenize = inAttribute(ch);
   1.118 +      return state.tokenize(stream, state);
   1.119 +    }
   1.120 +    else {
   1.121 +      stream.eatWhile(/[^\s\u00a0=<>\"\']/);
   1.122 +      return "word";
   1.123 +    }
   1.124 +  }
   1.125 +
   1.126 +  function inAttribute(quote) {
   1.127 +    return function(stream, state) {
   1.128 +      while (!stream.eol()) {
   1.129 +        if (stream.next() == quote) {
   1.130 +          state.tokenize = inTag;
   1.131 +          break;
   1.132 +        }
   1.133 +      }
   1.134 +      return "string";
   1.135 +    };
   1.136 +  }
   1.137 +
   1.138 +  function inBlock(style, terminator) {
   1.139 +    return function(stream, state) {
   1.140 +      while (!stream.eol()) {
   1.141 +        if (stream.match(terminator)) {
   1.142 +          state.tokenize = inText;
   1.143 +          break;
   1.144 +        }
   1.145 +        stream.next();
   1.146 +      }
   1.147 +      return style;
   1.148 +    };
   1.149 +  }
   1.150 +  function doctype(depth) {
   1.151 +    return function(stream, state) {
   1.152 +      var ch;
   1.153 +      while ((ch = stream.next()) != null) {
   1.154 +        if (ch == "<") {
   1.155 +          state.tokenize = doctype(depth + 1);
   1.156 +          return state.tokenize(stream, state);
   1.157 +        } else if (ch == ">") {
   1.158 +          if (depth == 1) {
   1.159 +            state.tokenize = inText;
   1.160 +            break;
   1.161 +          } else {
   1.162 +            state.tokenize = doctype(depth - 1);
   1.163 +            return state.tokenize(stream, state);
   1.164 +          }
   1.165 +        }
   1.166 +      }
   1.167 +      return "meta";
   1.168 +    };
   1.169 +  }
   1.170 +
   1.171 +  var curState, setStyle;
   1.172 +  function pass() {
   1.173 +    for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
   1.174 +  }
   1.175 +  function cont() {
   1.176 +    pass.apply(null, arguments);
   1.177 +    return true;
   1.178 +  }
   1.179 +
   1.180 +  function pushContext(tagName, startOfLine) {
   1.181 +    var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
   1.182 +    curState.context = {
   1.183 +      prev: curState.context,
   1.184 +      tagName: tagName,
   1.185 +      indent: curState.indented,
   1.186 +      startOfLine: startOfLine,
   1.187 +      noIndent: noIndent
   1.188 +    };
   1.189 +  }
   1.190 +  function popContext() {
   1.191 +    if (curState.context) curState.context = curState.context.prev;
   1.192 +  }
   1.193 +
   1.194 +  function element(type) {
   1.195 +    if (type == "openTag") {
   1.196 +      curState.tagName = tagName;
   1.197 +      return cont(attributes, endtag(curState.startOfLine));
   1.198 +    } else if (type == "closeTag") {
   1.199 +      var err = false;
   1.200 +      if (curState.context) {
   1.201 +        if (curState.context.tagName != tagName) {
   1.202 +          if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
   1.203 +            popContext();
   1.204 +          }
   1.205 +          err = !curState.context || curState.context.tagName != tagName;
   1.206 +        }
   1.207 +      } else {
   1.208 +        err = true;
   1.209 +      }
   1.210 +      if (err) setStyle = "error";
   1.211 +      return cont(endclosetag(err));
   1.212 +    }
   1.213 +    return cont();
   1.214 +  }
   1.215 +  function endtag(startOfLine) {
   1.216 +    return function(type) {
   1.217 +      var tagName = curState.tagName;
   1.218 +      curState.tagName = null;
   1.219 +      if (type == "selfcloseTag" ||
   1.220 +          (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
   1.221 +        maybePopContext(tagName.toLowerCase());
   1.222 +        return cont();
   1.223 +      }
   1.224 +      if (type == "endTag") {
   1.225 +        maybePopContext(tagName.toLowerCase());
   1.226 +        pushContext(tagName, startOfLine);
   1.227 +        return cont();
   1.228 +      }
   1.229 +      return cont();
   1.230 +    };
   1.231 +  }
   1.232 +  function endclosetag(err) {
   1.233 +    return function(type) {
   1.234 +      if (err) setStyle = "error";
   1.235 +      if (type == "endTag") { popContext(); return cont(); }
   1.236 +      setStyle = "error";
   1.237 +      return cont(arguments.callee);
   1.238 +    };
   1.239 +  }
   1.240 +  function maybePopContext(nextTagName) {
   1.241 +    var parentTagName;
   1.242 +    while (true) {
   1.243 +      if (!curState.context) {
   1.244 +        return;
   1.245 +      }
   1.246 +      parentTagName = curState.context.tagName.toLowerCase();
   1.247 +      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
   1.248 +          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
   1.249 +        return;
   1.250 +      }
   1.251 +      popContext();
   1.252 +    }
   1.253 +  }
   1.254 +
   1.255 +  function attributes(type) {
   1.256 +    if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
   1.257 +    if (type == "endTag" || type == "selfcloseTag") return pass();
   1.258 +    setStyle = "error";
   1.259 +    return cont(attributes);
   1.260 +  }
   1.261 +  function attribute(type) {
   1.262 +    if (type == "equals") return cont(attvalue, attributes);
   1.263 +    if (!Kludges.allowMissing) setStyle = "error";
   1.264 +    else if (type == "word") setStyle = "attribute";
   1.265 +    return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
   1.266 +  }
   1.267 +  function attvalue(type) {
   1.268 +    if (type == "string") return cont(attvaluemaybe);
   1.269 +    if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
   1.270 +    setStyle = "error";
   1.271 +    return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
   1.272 +  }
   1.273 +  function attvaluemaybe(type) {
   1.274 +    if (type == "string") return cont(attvaluemaybe);
   1.275 +    else return pass();
   1.276 +  }
   1.277 +
   1.278 +  return {
   1.279 +    startState: function() {
   1.280 +      return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
   1.281 +    },
   1.282 +
   1.283 +    token: function(stream, state) {
   1.284 +      if (stream.sol()) {
   1.285 +        state.startOfLine = true;
   1.286 +        state.indented = stream.indentation();
   1.287 +      }
   1.288 +      if (stream.eatSpace()) return null;
   1.289 +
   1.290 +      setStyle = type = tagName = null;
   1.291 +      var style = state.tokenize(stream, state);
   1.292 +      state.type = type;
   1.293 +      if ((style || type) && style != "comment") {
   1.294 +        curState = state;
   1.295 +        while (true) {
   1.296 +          var comb = state.cc.pop() || element;
   1.297 +          if (comb(type || style)) break;
   1.298 +        }
   1.299 +      }
   1.300 +      state.startOfLine = false;
   1.301 +      return setStyle || style;
   1.302 +    },
   1.303 +
   1.304 +    indent: function(state, textAfter, fullLine) {
   1.305 +      var context = state.context;
   1.306 +      if ((state.tokenize != inTag && state.tokenize != inText) ||
   1.307 +          context && context.noIndent)
   1.308 +        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
   1.309 +      if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
   1.310 +      if (context && /^<\//.test(textAfter))
   1.311 +        context = context.prev;
   1.312 +      while (context && !context.startOfLine)
   1.313 +        context = context.prev;
   1.314 +      if (context) return context.indent + indentUnit;
   1.315 +      else return 0;
   1.316 +    },
   1.317 +
   1.318 +    electricChars: "/",
   1.319 +
   1.320 +    configuration: parserConfig.htmlMode ? "html" : "xml"
   1.321 +  };
   1.322 +});
   1.323 +
   1.324 +CodeMirror.defineMIME("text/xml", "xml");
   1.325 +CodeMirror.defineMIME("application/xml", "xml");
   1.326 +if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
   1.327 +  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});