Merge branch '2.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / js / 3rdParty / codemirror / mode / xml / xml.js
CommitLineData
837afb80
TD
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";
10
77b7b761
TD
11CodeMirror.defineMode("xml", function(config, parserConfig) {
12 var indentUnit = config.indentUnit;
13 var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
837afb80
TD
14 var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
15 if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
77b7b761
TD
16
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,
837afb80
TD
47 allowMissing: true,
48 caseFold: true
77b7b761
TD
49 } : {
50 autoSelfClosers: {},
51 implicitlyClosed: {},
52 contextGrabbers: {},
53 doNotIndent: {},
54 allowUnquoted: false,
837afb80
TD
55 allowMissing: false,
56 caseFold: false
77b7b761
TD
57 };
58 var alignCDATA = parserConfig.alignCDATA;
59
60 // Return variables for tokenizers
837afb80 61 var tagName, type, setStyle;
77b7b761
TD
62
63 function inText(stream, state) {
64 function chain(parser) {
65 state.tokenize = parser;
66 return parser(stream, state);
67 }
68
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;
837afb80
TD
75 } else if (stream.match("--")) {
76 return chain(inBlock("comment", "-->"));
77 } else if (stream.match("DOCTYPE", true, true)) {
77b7b761
TD
78 stream.eatWhile(/[\w\._\-]/);
79 return chain(doctype(1));
837afb80
TD
80 } else {
81 return null;
77b7b761 82 }
837afb80 83 } else if (stream.eat("?")) {
77b7b761
TD
84 stream.eatWhile(/[\w\._\-]/);
85 state.tokenize = inBlock("meta", "?>");
86 return "meta";
837afb80 87 } else {
77b7b761
TD
88 var isClose = stream.eat("/");
89 tagName = "";
90 var c;
91 while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
837afb80
TD
92 if (Kludges.caseFold) tagName = tagName.toLowerCase();
93 if (!tagName) return "tag error";
77b7b761
TD
94 type = isClose ? "closeTag" : "openTag";
95 state.tokenize = inTag;
96 return "tag";
97 }
837afb80 98 } else if (ch == "&") {
77b7b761
TD
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";
837afb80 110 } else {
77b7b761
TD
111 stream.eatWhile(/[^&<]/);
112 return null;
113 }
114 }
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";
837afb80 122 } else if (ch == "=") {
77b7b761
TD
123 type = "equals";
124 return null;
837afb80
TD
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)) {
77b7b761 132 state.tokenize = inAttribute(ch);
837afb80 133 state.stringStartCol = stream.column();
77b7b761 134 return state.tokenize(stream, state);
837afb80 135 } else {
77b7b761
TD
136 stream.eatWhile(/[^\s\u00a0=<>\"\']/);
137 return "word";
138 }
139 }
140
141 function inAttribute(quote) {
837afb80 142 var closure = function(stream, state) {
77b7b761
TD
143 while (!stream.eol()) {
144 if (stream.next() == quote) {
145 state.tokenize = inTag;
146 break;
147 }
148 }
149 return "string";
150 };
837afb80
TD
151 closure.isInAttribute = true;
152 return closure;
77b7b761
TD
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
837afb80
TD
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;
77b7b761 195 }
837afb80
TD
196 function popContext(state) {
197 if (state.context) state.context = state.context.prev;
77b7b761 198 }
837afb80
TD
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 }
77b7b761
TD
212 }
213
837afb80 214 function baseState(type, stream, state) {
77b7b761 215 if (type == "openTag") {
837afb80
TD
216 state.tagName = tagName;
217 state.tagStart = stream.column();
218 return attrState;
77b7b761
TD
219 } else if (type == "closeTag") {
220 var err = false;
837afb80
TD
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;
77b7b761
TD
226 }
227 } else {
228 err = true;
229 }
230 if (err) setStyle = "error";
837afb80
TD
231 return err ? closeStateErr : closeState;
232 } else {
233 return baseState;
77b7b761 234 }
77b7b761 235 }
837afb80
TD
236
237 function closeState(type, _stream, state) {
238 if (type != "endTag") {
77b7b761 239 setStyle = "error";
837afb80 240 return closeState;
77b7b761 241 }
837afb80
TD
242 popContext(state);
243 return baseState;
244 }
245 function closeStateErr(type, stream, state) {
246 setStyle = "error";
247 return closeState(type, stream, state);
77b7b761
TD
248 }
249
837afb80
TD
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 }
77b7b761 266 setStyle = "error";
837afb80 267 return attrState;
77b7b761 268 }
837afb80
TD
269 function attrEqState(type, stream, state) {
270 if (type == "equals") return attrValueState;
77b7b761 271 if (!Kludges.allowMissing) setStyle = "error";
837afb80 272 return attrState(type, stream, state);
77b7b761 273 }
837afb80
TD
274 function attrValueState(type, stream, state) {
275 if (type == "string") return attrContinuedState;
276 if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
77b7b761 277 setStyle = "error";
837afb80 278 return attrState(type, stream, state);
77b7b761 279 }
837afb80
TD
280 function attrContinuedState(type, stream, state) {
281 if (type == "string") return attrContinuedState;
282 return attrState(type, stream, state);
77b7b761
TD
283 }
284
285 return {
286 startState: function() {
837afb80
TD
287 return {tokenize: inText,
288 state: baseState,
289 indented: 0,
290 tagName: null, tagStart: null,
291 context: null};
77b7b761
TD
292 },
293
294 token: function(stream, state) {
837afb80 295 if (!state.tagName && stream.sol())
77b7b761 296 state.indented = stream.indentation();
77b7b761 297
837afb80
TD
298 if (stream.eatSpace()) return null;
299 tagName = type = null;
77b7b761 300 var style = state.tokenize(stream, state);
77b7b761 301 if ((style || type) && style != "comment") {
837afb80
TD
302 setStyle = null;
303 state.state = state.state(type || style, stream, state);
304 if (setStyle)
305 style = setStyle == "error" ? style + " error" : setStyle;
77b7b761 306 }
837afb80 307 return style;
77b7b761
TD
308 },
309
310 indent: function(state, textAfter, fullLine) {
311 var context = state.context;
837afb80
TD
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)
77b7b761 318 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
837afb80
TD
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 }
77b7b761
TD
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 },
334
335 electricChars: "/",
336 blockCommentStart: "<!--",
337 blockCommentEnd: "-->",
338
837afb80
TD
339 configuration: parserConfig.htmlMode ? "html" : "xml",
340 helperType: parserConfig.htmlMode ? "html" : "xml"
77b7b761
TD
341 };
342});
343
344CodeMirror.defineMIME("text/xml", "xml");
345CodeMirror.defineMIME("application/xml", "xml");
346if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
347 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
837afb80
TD
348
349});