openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

xml.js (12570B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 (function(mod) {
      5   if (typeof exports == "object" && typeof module == "object") // CommonJS
      6     mod(require("../../lib/codemirror"));
      7   else if (typeof define == "function" && define.amd) // AMD
      8     define(["../../lib/codemirror"], mod);
      9   else // Plain browser env
     10     mod(CodeMirror);
     11 })(function(CodeMirror) {
     12 "use strict";
     13 
     14 var htmlConfig = {
     15   autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
     16                     'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
     17                     'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
     18                     'track': true, 'wbr': true, 'menuitem': true},
     19   implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
     20                      'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
     21                      'th': true, 'tr': true},
     22   contextGrabbers: {
     23     'dd': {'dd': true, 'dt': true},
     24     'dt': {'dd': true, 'dt': true},
     25     'li': {'li': true},
     26     'option': {'option': true, 'optgroup': true},
     27     'optgroup': {'optgroup': true},
     28     'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
     29           'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
     30           'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
     31           'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
     32           'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
     33     'rp': {'rp': true, 'rt': true},
     34     'rt': {'rp': true, 'rt': true},
     35     'tbody': {'tbody': true, 'tfoot': true},
     36     'td': {'td': true, 'th': true},
     37     'tfoot': {'tbody': true},
     38     'th': {'td': true, 'th': true},
     39     'thead': {'tbody': true, 'tfoot': true},
     40     'tr': {'tr': true}
     41   },
     42   doNotIndent: {"pre": true},
     43   allowUnquoted: true,
     44   allowMissing: true,
     45   caseFold: true
     46 }
     47 
     48 var xmlConfig = {
     49   autoSelfClosers: {},
     50   implicitlyClosed: {},
     51   contextGrabbers: {},
     52   doNotIndent: {},
     53   allowUnquoted: false,
     54   allowMissing: false,
     55   caseFold: false
     56 }
     57 
     58 CodeMirror.defineMode("xml", function(editorConf, config_) {
     59   var indentUnit = editorConf.indentUnit
     60   var config = {}
     61   var defaults = config_.htmlMode ? htmlConfig : xmlConfig
     62   for (var prop in defaults) config[prop] = defaults[prop]
     63   for (var prop in config_) config[prop] = config_[prop]
     64 
     65   // Return variables for tokenizers
     66   var type, setStyle;
     67 
     68   function inText(stream, state) {
     69     function chain(parser) {
     70       state.tokenize = parser;
     71       return parser(stream, state);
     72     }
     73 
     74     var ch = stream.next();
     75     if (ch == "<") {
     76       if (stream.eat("!")) {
     77         if (stream.eat("[")) {
     78           if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
     79           else return null;
     80         } else if (stream.match("--")) {
     81           return chain(inBlock("comment", "-->"));
     82         } else if (stream.match("DOCTYPE", true, true)) {
     83           stream.eatWhile(/[\w\._\-]/);
     84           return chain(doctype(1));
     85         } else {
     86           return null;
     87         }
     88       } else if (stream.eat("?")) {
     89         stream.eatWhile(/[\w\._\-]/);
     90         state.tokenize = inBlock("meta", "?>");
     91         return "meta";
     92       } else {
     93         type = stream.eat("/") ? "closeTag" : "openTag";
     94         state.tokenize = inTag;
     95         return "tag bracket";
     96       }
     97     } else if (ch == "&") {
     98       var ok;
     99       if (stream.eat("#")) {
    100         if (stream.eat("x")) {
    101           ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
    102         } else {
    103           ok = stream.eatWhile(/[\d]/) && stream.eat(";");
    104         }
    105       } else {
    106         ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
    107       }
    108       return ok ? "atom" : "error";
    109     } else {
    110       stream.eatWhile(/[^&<]/);
    111       return null;
    112     }
    113   }
    114   inText.isInText = true;
    115 
    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 bracket";
    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 + " tag error" : "tag 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.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
    137       return "word";
    138     }
    139   }
    140 
    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   }
    154 
    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   }
    187 
    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 (config.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 (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
    207           !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
    208         return;
    209       }
    210       popContext(state);
    211     }
    212   }
    213 
    214   function baseState(type, stream, state) {
    215     if (type == "openTag") {
    216       state.tagStart = stream.column();
    217       return tagNameState;
    218     } else if (type == "closeTag") {
    219       return closeTagNameState;
    220     } else {
    221       return baseState;
    222     }
    223   }
    224   function tagNameState(type, stream, state) {
    225     if (type == "word") {
    226       state.tagName = stream.current();
    227       setStyle = "tag";
    228       return attrState;
    229     } else {
    230       setStyle = "error";
    231       return tagNameState;
    232     }
    233   }
    234   function closeTagNameState(type, stream, state) {
    235     if (type == "word") {
    236       var tagName = stream.current();
    237       if (state.context && state.context.tagName != tagName &&
    238           config.implicitlyClosed.hasOwnProperty(state.context.tagName))
    239         popContext(state);
    240       if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
    241         setStyle = "tag";
    242         return closeState;
    243       } else {
    244         setStyle = "tag error";
    245         return closeStateErr;
    246       }
    247     } else {
    248       setStyle = "error";
    249       return closeStateErr;
    250     }
    251   }
    252 
    253   function closeState(type, _stream, state) {
    254     if (type != "endTag") {
    255       setStyle = "error";
    256       return closeState;
    257     }
    258     popContext(state);
    259     return baseState;
    260   }
    261   function closeStateErr(type, stream, state) {
    262     setStyle = "error";
    263     return closeState(type, stream, state);
    264   }
    265 
    266   function attrState(type, _stream, state) {
    267     if (type == "word") {
    268       setStyle = "attribute";
    269       return attrEqState;
    270     } else if (type == "endTag" || type == "selfcloseTag") {
    271       var tagName = state.tagName, tagStart = state.tagStart;
    272       state.tagName = state.tagStart = null;
    273       if (type == "selfcloseTag" ||
    274           config.autoSelfClosers.hasOwnProperty(tagName)) {
    275         maybePopContext(state, tagName);
    276       } else {
    277         maybePopContext(state, tagName);
    278         state.context = new Context(state, tagName, tagStart == state.indented);
    279       }
    280       return baseState;
    281     }
    282     setStyle = "error";
    283     return attrState;
    284   }
    285   function attrEqState(type, stream, state) {
    286     if (type == "equals") return attrValueState;
    287     if (!config.allowMissing) setStyle = "error";
    288     return attrState(type, stream, state);
    289   }
    290   function attrValueState(type, stream, state) {
    291     if (type == "string") return attrContinuedState;
    292     if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
    293     setStyle = "error";
    294     return attrState(type, stream, state);
    295   }
    296   function attrContinuedState(type, stream, state) {
    297     if (type == "string") return attrContinuedState;
    298     return attrState(type, stream, state);
    299   }
    300 
    301   return {
    302     startState: function(baseIndent) {
    303       var state = {tokenize: inText,
    304                    state: baseState,
    305                    indented: baseIndent || 0,
    306                    tagName: null, tagStart: null,
    307                    context: null}
    308       if (baseIndent != null) state.baseIndent = baseIndent
    309       return state
    310     },
    311 
    312     token: function(stream, state) {
    313       if (!state.tagName && stream.sol())
    314         state.indented = stream.indentation();
    315 
    316       if (stream.eatSpace()) return null;
    317       type = null;
    318       var style = state.tokenize(stream, state);
    319       if ((style || type) && style != "comment") {
    320         setStyle = null;
    321         state.state = state.state(type || style, stream, state);
    322         if (setStyle)
    323           style = setStyle == "error" ? style + " error" : setStyle;
    324       }
    325       return style;
    326     },
    327 
    328     indent: function(state, textAfter, fullLine) {
    329       var context = state.context;
    330       // Indent multi-line strings (e.g. css).
    331       if (state.tokenize.isInAttribute) {
    332         if (state.tagStart == state.indented)
    333           return state.stringStartCol + 1;
    334         else
    335           return state.indented + indentUnit;
    336       }
    337       if (context && context.noIndent) return CodeMirror.Pass;
    338       if (state.tokenize != inTag && state.tokenize != inText)
    339         return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
    340       // Indent the starts of attribute names.
    341       if (state.tagName) {
    342         if (config.multilineTagIndentPastTag !== false)
    343           return state.tagStart + state.tagName.length + 2;
    344         else
    345           return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
    346       }
    347       if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
    348       var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
    349       if (tagAfter && tagAfter[1]) { // Closing tag spotted
    350         while (context) {
    351           if (context.tagName == tagAfter[2]) {
    352             context = context.prev;
    353             break;
    354           } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
    355             context = context.prev;
    356           } else {
    357             break;
    358           }
    359         }
    360       } else if (tagAfter) { // Opening tag spotted
    361         while (context) {
    362           var grabbers = config.contextGrabbers[context.tagName];
    363           if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
    364             context = context.prev;
    365           else
    366             break;
    367         }
    368       }
    369       while (context && context.prev && !context.startOfLine)
    370         context = context.prev;
    371       if (context) return context.indent + indentUnit;
    372       else return state.baseIndent || 0;
    373     },
    374 
    375     electricInput: /<\/[\s\w:]+>$/,
    376     blockCommentStart: "<!--",
    377     blockCommentEnd: "-->",
    378 
    379     configuration: config.htmlMode ? "html" : "xml",
    380     helperType: config.htmlMode ? "html" : "xml",
    381 
    382     skipAttribute: function(state) {
    383       if (state.state == attrValueState)
    384         state.state = attrState
    385     }
    386   };
    387 });
    388 
    389 CodeMirror.defineMIME("text/xml", "xml");
    390 CodeMirror.defineMIME("application/xml", "xml");
    391 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
    392   CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
    393 
    394 });