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.

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

mercurial