browser/devtools/sourceeditor/codemirror/xml.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 (function(mod) {
michael@0 2 if (typeof exports == "object" && typeof module == "object") // CommonJS
michael@0 3 mod(require("../../lib/codemirror"));
michael@0 4 else if (typeof define == "function" && define.amd) // AMD
michael@0 5 define(["../../lib/codemirror"], mod);
michael@0 6 else // Plain browser env
michael@0 7 mod(CodeMirror);
michael@0 8 })(function(CodeMirror) {
michael@0 9 "use strict";
michael@0 10
michael@0 11 CodeMirror.defineMode("xml", function(config, parserConfig) {
michael@0 12 var indentUnit = config.indentUnit;
michael@0 13 var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
michael@0 14 var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
michael@0 15 if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
michael@0 16
michael@0 17 var Kludges = parserConfig.htmlMode ? {
michael@0 18 autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
michael@0 19 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
michael@0 20 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
michael@0 21 'track': true, 'wbr': true},
michael@0 22 implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
michael@0 23 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
michael@0 24 'th': true, 'tr': true},
michael@0 25 contextGrabbers: {
michael@0 26 'dd': {'dd': true, 'dt': true},
michael@0 27 'dt': {'dd': true, 'dt': true},
michael@0 28 'li': {'li': true},
michael@0 29 'option': {'option': true, 'optgroup': true},
michael@0 30 'optgroup': {'optgroup': true},
michael@0 31 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
michael@0 32 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
michael@0 33 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
michael@0 34 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
michael@0 35 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
michael@0 36 'rp': {'rp': true, 'rt': true},
michael@0 37 'rt': {'rp': true, 'rt': true},
michael@0 38 'tbody': {'tbody': true, 'tfoot': true},
michael@0 39 'td': {'td': true, 'th': true},
michael@0 40 'tfoot': {'tbody': true},
michael@0 41 'th': {'td': true, 'th': true},
michael@0 42 'thead': {'tbody': true, 'tfoot': true},
michael@0 43 'tr': {'tr': true}
michael@0 44 },
michael@0 45 doNotIndent: {"pre": true},
michael@0 46 allowUnquoted: true,
michael@0 47 allowMissing: true,
michael@0 48 caseFold: true
michael@0 49 } : {
michael@0 50 autoSelfClosers: {},
michael@0 51 implicitlyClosed: {},
michael@0 52 contextGrabbers: {},
michael@0 53 doNotIndent: {},
michael@0 54 allowUnquoted: false,
michael@0 55 allowMissing: false,
michael@0 56 caseFold: false
michael@0 57 };
michael@0 58 var alignCDATA = parserConfig.alignCDATA;
michael@0 59
michael@0 60 // Return variables for tokenizers
michael@0 61 var tagName, type, setStyle;
michael@0 62
michael@0 63 function inText(stream, state) {
michael@0 64 function chain(parser) {
michael@0 65 state.tokenize = parser;
michael@0 66 return parser(stream, state);
michael@0 67 }
michael@0 68
michael@0 69 var ch = stream.next();
michael@0 70 if (ch == "<") {
michael@0 71 if (stream.eat("!")) {
michael@0 72 if (stream.eat("[")) {
michael@0 73 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
michael@0 74 else return null;
michael@0 75 } else if (stream.match("--")) {
michael@0 76 return chain(inBlock("comment", "-->"));
michael@0 77 } else if (stream.match("DOCTYPE", true, true)) {
michael@0 78 stream.eatWhile(/[\w\._\-]/);
michael@0 79 return chain(doctype(1));
michael@0 80 } else {
michael@0 81 return null;
michael@0 82 }
michael@0 83 } else if (stream.eat("?")) {
michael@0 84 stream.eatWhile(/[\w\._\-]/);
michael@0 85 state.tokenize = inBlock("meta", "?>");
michael@0 86 return "meta";
michael@0 87 } else {
michael@0 88 var isClose = stream.eat("/");
michael@0 89 tagName = "";
michael@0 90 var c;
michael@0 91 while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
michael@0 92 if (Kludges.caseFold) tagName = tagName.toLowerCase();
michael@0 93 if (!tagName) return "tag error";
michael@0 94 type = isClose ? "closeTag" : "openTag";
michael@0 95 state.tokenize = inTag;
michael@0 96 return "tag";
michael@0 97 }
michael@0 98 } else if (ch == "&") {
michael@0 99 var ok;
michael@0 100 if (stream.eat("#")) {
michael@0 101 if (stream.eat("x")) {
michael@0 102 ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
michael@0 103 } else {
michael@0 104 ok = stream.eatWhile(/[\d]/) && stream.eat(";");
michael@0 105 }
michael@0 106 } else {
michael@0 107 ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
michael@0 108 }
michael@0 109 return ok ? "atom" : "error";
michael@0 110 } else {
michael@0 111 stream.eatWhile(/[^&<]/);
michael@0 112 return null;
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 function inTag(stream, state) {
michael@0 117 var ch = stream.next();
michael@0 118 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
michael@0 119 state.tokenize = inText;
michael@0 120 type = ch == ">" ? "endTag" : "selfcloseTag";
michael@0 121 return "tag";
michael@0 122 } else if (ch == "=") {
michael@0 123 type = "equals";
michael@0 124 return null;
michael@0 125 } else if (ch == "<") {
michael@0 126 state.tokenize = inText;
michael@0 127 state.state = baseState;
michael@0 128 state.tagName = state.tagStart = null;
michael@0 129 var next = state.tokenize(stream, state);
michael@0 130 return next ? next + " error" : "error";
michael@0 131 } else if (/[\'\"]/.test(ch)) {
michael@0 132 state.tokenize = inAttribute(ch);
michael@0 133 state.stringStartCol = stream.column();
michael@0 134 return state.tokenize(stream, state);
michael@0 135 } else {
michael@0 136 stream.eatWhile(/[^\s\u00a0=<>\"\']/);
michael@0 137 return "word";
michael@0 138 }
michael@0 139 }
michael@0 140
michael@0 141 function inAttribute(quote) {
michael@0 142 var closure = function(stream, state) {
michael@0 143 while (!stream.eol()) {
michael@0 144 if (stream.next() == quote) {
michael@0 145 state.tokenize = inTag;
michael@0 146 break;
michael@0 147 }
michael@0 148 }
michael@0 149 return "string";
michael@0 150 };
michael@0 151 closure.isInAttribute = true;
michael@0 152 return closure;
michael@0 153 }
michael@0 154
michael@0 155 function inBlock(style, terminator) {
michael@0 156 return function(stream, state) {
michael@0 157 while (!stream.eol()) {
michael@0 158 if (stream.match(terminator)) {
michael@0 159 state.tokenize = inText;
michael@0 160 break;
michael@0 161 }
michael@0 162 stream.next();
michael@0 163 }
michael@0 164 return style;
michael@0 165 };
michael@0 166 }
michael@0 167 function doctype(depth) {
michael@0 168 return function(stream, state) {
michael@0 169 var ch;
michael@0 170 while ((ch = stream.next()) != null) {
michael@0 171 if (ch == "<") {
michael@0 172 state.tokenize = doctype(depth + 1);
michael@0 173 return state.tokenize(stream, state);
michael@0 174 } else if (ch == ">") {
michael@0 175 if (depth == 1) {
michael@0 176 state.tokenize = inText;
michael@0 177 break;
michael@0 178 } else {
michael@0 179 state.tokenize = doctype(depth - 1);
michael@0 180 return state.tokenize(stream, state);
michael@0 181 }
michael@0 182 }
michael@0 183 }
michael@0 184 return "meta";
michael@0 185 };
michael@0 186 }
michael@0 187
michael@0 188 function Context(state, tagName, startOfLine) {
michael@0 189 this.prev = state.context;
michael@0 190 this.tagName = tagName;
michael@0 191 this.indent = state.indented;
michael@0 192 this.startOfLine = startOfLine;
michael@0 193 if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
michael@0 194 this.noIndent = true;
michael@0 195 }
michael@0 196 function popContext(state) {
michael@0 197 if (state.context) state.context = state.context.prev;
michael@0 198 }
michael@0 199 function maybePopContext(state, nextTagName) {
michael@0 200 var parentTagName;
michael@0 201 while (true) {
michael@0 202 if (!state.context) {
michael@0 203 return;
michael@0 204 }
michael@0 205 parentTagName = state.context.tagName;
michael@0 206 if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
michael@0 207 !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
michael@0 208 return;
michael@0 209 }
michael@0 210 popContext(state);
michael@0 211 }
michael@0 212 }
michael@0 213
michael@0 214 function baseState(type, stream, state) {
michael@0 215 if (type == "openTag") {
michael@0 216 state.tagName = tagName;
michael@0 217 state.tagStart = stream.column();
michael@0 218 return attrState;
michael@0 219 } else if (type == "closeTag") {
michael@0 220 var err = false;
michael@0 221 if (state.context) {
michael@0 222 if (state.context.tagName != tagName) {
michael@0 223 if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
michael@0 224 popContext(state);
michael@0 225 err = !state.context || state.context.tagName != tagName;
michael@0 226 }
michael@0 227 } else {
michael@0 228 err = true;
michael@0 229 }
michael@0 230 if (err) setStyle = "error";
michael@0 231 return err ? closeStateErr : closeState;
michael@0 232 } else {
michael@0 233 return baseState;
michael@0 234 }
michael@0 235 }
michael@0 236
michael@0 237 function closeState(type, _stream, state) {
michael@0 238 if (type != "endTag") {
michael@0 239 setStyle = "error";
michael@0 240 return closeState;
michael@0 241 }
michael@0 242 popContext(state);
michael@0 243 return baseState;
michael@0 244 }
michael@0 245 function closeStateErr(type, stream, state) {
michael@0 246 setStyle = "error";
michael@0 247 return closeState(type, stream, state);
michael@0 248 }
michael@0 249
michael@0 250 function attrState(type, _stream, state) {
michael@0 251 if (type == "word") {
michael@0 252 setStyle = "attribute";
michael@0 253 return attrEqState;
michael@0 254 } else if (type == "endTag" || type == "selfcloseTag") {
michael@0 255 var tagName = state.tagName, tagStart = state.tagStart;
michael@0 256 state.tagName = state.tagStart = null;
michael@0 257 if (type == "selfcloseTag" ||
michael@0 258 Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
michael@0 259 maybePopContext(state, tagName);
michael@0 260 } else {
michael@0 261 maybePopContext(state, tagName);
michael@0 262 state.context = new Context(state, tagName, tagStart == state.indented);
michael@0 263 }
michael@0 264 return baseState;
michael@0 265 }
michael@0 266 setStyle = "error";
michael@0 267 return attrState;
michael@0 268 }
michael@0 269 function attrEqState(type, stream, state) {
michael@0 270 if (type == "equals") return attrValueState;
michael@0 271 if (!Kludges.allowMissing) setStyle = "error";
michael@0 272 return attrState(type, stream, state);
michael@0 273 }
michael@0 274 function attrValueState(type, stream, state) {
michael@0 275 if (type == "string") return attrContinuedState;
michael@0 276 if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
michael@0 277 setStyle = "error";
michael@0 278 return attrState(type, stream, state);
michael@0 279 }
michael@0 280 function attrContinuedState(type, stream, state) {
michael@0 281 if (type == "string") return attrContinuedState;
michael@0 282 return attrState(type, stream, state);
michael@0 283 }
michael@0 284
michael@0 285 return {
michael@0 286 startState: function() {
michael@0 287 return {tokenize: inText,
michael@0 288 state: baseState,
michael@0 289 indented: 0,
michael@0 290 tagName: null, tagStart: null,
michael@0 291 context: null};
michael@0 292 },
michael@0 293
michael@0 294 token: function(stream, state) {
michael@0 295 if (!state.tagName && stream.sol())
michael@0 296 state.indented = stream.indentation();
michael@0 297
michael@0 298 if (stream.eatSpace()) return null;
michael@0 299 tagName = type = null;
michael@0 300 var style = state.tokenize(stream, state);
michael@0 301 if ((style || type) && style != "comment") {
michael@0 302 setStyle = null;
michael@0 303 state.state = state.state(type || style, stream, state);
michael@0 304 if (setStyle)
michael@0 305 style = setStyle == "error" ? style + " error" : setStyle;
michael@0 306 }
michael@0 307 return style;
michael@0 308 },
michael@0 309
michael@0 310 indent: function(state, textAfter, fullLine) {
michael@0 311 var context = state.context;
michael@0 312 // Indent multi-line strings (e.g. css).
michael@0 313 if (state.tokenize.isInAttribute) {
michael@0 314 return state.stringStartCol + 1;
michael@0 315 }
michael@0 316 if (context && context.noIndent) return CodeMirror.Pass;
michael@0 317 if (state.tokenize != inTag && state.tokenize != inText)
michael@0 318 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
michael@0 319 // Indent the starts of attribute names.
michael@0 320 if (state.tagName) {
michael@0 321 if (multilineTagIndentPastTag)
michael@0 322 return state.tagStart + state.tagName.length + 2;
michael@0 323 else
michael@0 324 return state.tagStart + indentUnit * multilineTagIndentFactor;
michael@0 325 }
michael@0 326 if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
michael@0 327 if (context && /^<\//.test(textAfter))
michael@0 328 context = context.prev;
michael@0 329 while (context && !context.startOfLine)
michael@0 330 context = context.prev;
michael@0 331 if (context) return context.indent + indentUnit;
michael@0 332 else return 0;
michael@0 333 },
michael@0 334
michael@0 335 electricChars: "/",
michael@0 336 blockCommentStart: "<!--",
michael@0 337 blockCommentEnd: "-->",
michael@0 338
michael@0 339 configuration: parserConfig.htmlMode ? "html" : "xml",
michael@0 340 helperType: parserConfig.htmlMode ? "html" : "xml"
michael@0 341 };
michael@0 342 });
michael@0 343
michael@0 344 CodeMirror.defineMIME("text/xml", "xml");
michael@0 345 CodeMirror.defineMIME("application/xml", "xml");
michael@0 346 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
michael@0 347 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
michael@0 348
michael@0 349 });

mercurial