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
8 })(function(CodeMirror
) {
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},
26 'dd': {'dd': true, 'dt': true},
27 'dt': {'dd': true, 'dt': 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},
45 doNotIndent
: {"pre": true},
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
);
69 var ch
= stream
.next();
71 if (stream
.eat("!")) {
72 if (stream
.eat("[")) {
73 if (stream
.match("CDATA[")) return chain(inBlock("atom", "]]>"));
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));
83 } else if (stream
.eat("?")) {
84 stream
.eatWhile(/[\w\._\-]/);
85 state
.tokenize
= inBlock("meta", "?>");
88 var isClose
= stream
.eat("/");
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
;
98 } else if (ch
== "&") {
100 if (stream
.eat("#")) {
101 if (stream
.eat("x")) {
102 ok
= stream
.eatWhile(/[a-fA-F\d]/) && stream
.eat(";");
104 ok
= stream
.eatWhile(/[\d]/) && stream
.eat(";");
107 ok
= stream
.eatWhile(/[\w\.\-:]/) && stream
.eat(";");
109 return ok
? "atom" : "error";
111 stream
.eatWhile(/[^&<]/);
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";
122 } else if (ch
== "=") {
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
);
136 stream
.eatWhile(/[^\s\u00a0=<>\"\']/);
141 function inAttribute(quote
) {
142 var closure = function(stream
, state
) {
143 while (!stream
.eol()) {
144 if (stream
.next() == quote
) {
145 state
.tokenize
= inTag
;
151 closure
.isInAttribute
= true;
155 function inBlock(style
, terminator
) {
156 return function(stream
, state
) {
157 while (!stream
.eol()) {
158 if (stream
.match(terminator
)) {
159 state
.tokenize
= inText
;
167 function doctype(depth
) {
168 return function(stream
, state
) {
170 while ((ch
= stream
.next()) != null) {
172 state
.tokenize
= doctype(depth
+ 1);
173 return state
.tokenize(stream
, state
);
174 } else if (ch
== ">") {
176 state
.tokenize
= inText
;
179 state
.tokenize
= doctype(depth
- 1);
180 return state
.tokenize(stream
, state
);
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;
196 function popContext(state
) {
197 if (state
.context
) state
.context
= state
.context
.prev
;
199 function maybePopContext(state
, nextTagName
) {
202 if (!state
.context
) {
205 parentTagName
= state
.context
.tagName
;
206 if (!Kludges
.contextGrabbers
.hasOwnProperty(parentTagName
) ||
207 !Kludges
.contextGrabbers
[parentTagName
].hasOwnProperty(nextTagName
)) {
214 function baseState(type
, stream
, state
) {
215 if (type
== "openTag") {
216 state
.tagName
= tagName
;
217 state
.tagStart
= stream
.column();
219 } else if (type
== "closeTag") {
222 if (state
.context
.tagName
!= tagName
) {
223 if (Kludges
.implicitlyClosed
.hasOwnProperty(state
.context
.tagName
))
225 err
= !state
.context
|| state
.context
.tagName
!= tagName
;
230 if (err
) setStyle
= "error";
231 return err
? closeStateErr
: closeState
;
237 function closeState(type
, _stream
, state
) {
238 if (type
!= "endTag") {
245 function closeStateErr(type
, stream
, state
) {
247 return closeState(type
, stream
, state
);
250 function attrState(type
, _stream
, state
) {
251 if (type
== "word") {
252 setStyle
= "attribute";
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
);
261 maybePopContext(state
, tagName
);
262 state
.context
= new Context(state
, tagName
, tagStart
== state
.indented
);
269 function attrEqState(type
, stream
, state
) {
270 if (type
== "equals") return attrValueState
;
271 if (!Kludges
.allowMissing
) setStyle
= "error";
272 return attrState(type
, stream
, state
);
274 function attrValueState(type
, stream
, state
) {
275 if (type
== "string") return attrContinuedState
;
276 if (type
== "word" && Kludges
.allowUnquoted
) {setStyle
= "string"; return attrState
;}
278 return attrState(type
, stream
, state
);
280 function attrContinuedState(type
, stream
, state
) {
281 if (type
== "string") return attrContinuedState
;
282 return attrState(type
, stream
, state
);
286 startState: function() {
287 return {tokenize
: inText
,
290 tagName
: null, tagStart
: null,
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") {
303 state
.state
= state
.state(type
|| style
, stream
, state
);
305 style
= setStyle
== "error" ? style
+ " error" : setStyle
;
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;
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.
321 if (multilineTagIndentPastTag
)
322 return state
.tagStart
+ state
.tagName
.length
+ 2;
324 return state
.tagStart
+ indentUnit
* multilineTagIndentFactor
;
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
;
336 blockCommentStart
: "<!--",
337 blockCommentEnd
: "-->",
339 configuration
: parserConfig
.htmlMode
? "html" : "xml",
340 helperType
: parserConfig
.htmlMode
? "html" : "xml"
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});