aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/xml/xml.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/xml/xml.js')
-rwxr-xr-ximports/codemirror/mode/xml/xml.js252
1 files changed, 252 insertions, 0 deletions
diff --git a/imports/codemirror/mode/xml/xml.js b/imports/codemirror/mode/xml/xml.js
new file mode 100755
index 00000000..71e0e2b0
--- /dev/null
+++ b/imports/codemirror/mode/xml/xml.js
@@ -0,0 +1,252 @@
1CodeMirror.defineMode("xml", function(config, parserConfig) {
2 var indentUnit = config.indentUnit;
3 var Kludges = parserConfig.htmlMode ? {
4 autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
5 "meta": true, "col": true, "frame": true, "base": true, "area": true},
6 doNotIndent: {"pre": true},
7 allowUnquoted: true
8 } : {autoSelfClosers: {}, doNotIndent: {}, allowUnquoted: false};
9 var alignCDATA = parserConfig.alignCDATA;
10
11 // Return variables for tokenizers
12 var tagName, type;
13
14 function inText(stream, state) {
15 function chain(parser) {
16 state.tokenize = parser;
17 return parser(stream, state);
18 }
19
20 var ch = stream.next();
21 if (ch == "<") {
22 if (stream.eat("!")) {
23 if (stream.eat("[")) {
24 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
25 else return null;
26 }
27 else if (stream.match("--")) return chain(inBlock("comment", "-->"));
28 else if (stream.match("DOCTYPE", true, true)) {
29 stream.eatWhile(/[\w\._\-]/);
30 return chain(doctype(1));
31 }
32 else return null;
33 }
34 else if (stream.eat("?")) {
35 stream.eatWhile(/[\w\._\-]/);
36 state.tokenize = inBlock("meta", "?>");
37 return "meta";
38 }
39 else {
40 type = stream.eat("/") ? "closeTag" : "openTag";
41 stream.eatSpace();
42 tagName = "";
43 var c;
44 while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
45 state.tokenize = inTag;
46 return "tag";
47 }
48 }
49 else if (ch == "&") {
50 stream.eatWhile(/[^;]/);
51 stream.eat(";");
52 return "atom";
53 }
54 else {
55 stream.eatWhile(/[^&<]/);
56 return null;
57 }
58 }
59
60 function inTag(stream, state) {
61 var ch = stream.next();
62 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
63 state.tokenize = inText;
64 type = ch == ">" ? "endTag" : "selfcloseTag";
65 return "tag";
66 }
67 else if (ch == "=") {
68 type = "equals";
69 return null;
70 }
71 else if (/[\'\"]/.test(ch)) {
72 state.tokenize = inAttribute(ch);
73 return state.tokenize(stream, state);
74 }
75 else {
76 stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
77 return "word";
78 }
79 }
80
81 function inAttribute(quote) {
82 return function(stream, state) {
83 while (!stream.eol()) {
84 if (stream.next() == quote) {
85 state.tokenize = inTag;
86 break;
87 }
88 }
89 return "string";
90 };
91 }
92
93 function inBlock(style, terminator) {
94 return function(stream, state) {
95 while (!stream.eol()) {
96 if (stream.match(terminator)) {
97 state.tokenize = inText;
98 break;
99 }
100 stream.next();
101 }
102 return style;
103 };
104 }
105 function doctype(depth) {
106 return function(stream, state) {
107 var ch;
108 while ((ch = stream.next()) != null) {
109 if (ch == "<") {
110 state.tokenize = doctype(depth + 1);
111 return state.tokenize(stream, state);
112 } else if (ch == ">") {
113 if (depth == 1) {
114 state.tokenize = inText;
115 break;
116 } else {
117 state.tokenize = doctype(depth - 1);
118 return state.tokenize(stream, state);
119 }
120 }
121 }
122 return "meta";
123 };
124 }
125
126 var curState, setStyle;
127 function pass() {
128 for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
129 }
130 function cont() {
131 pass.apply(null, arguments);
132 return true;
133 }
134
135 function pushContext(tagName, startOfLine) {
136 var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
137 curState.context = {
138 prev: curState.context,
139 tagName: tagName,
140 indent: curState.indented,
141 startOfLine: startOfLine,
142 noIndent: noIndent
143 };
144 }
145 function popContext() {
146 if (curState.context) curState.context = curState.context.prev;
147 }
148
149 function element(type) {
150 if (type == "openTag") {
151 curState.tagName = tagName;
152 return cont(attributes, endtag(curState.startOfLine));
153 } else if (type == "closeTag") {
154 var err = false;
155 if (curState.context) {
156 err = curState.context.tagName != tagName;
157 } else {
158 err = true;
159 }
160 if (err) setStyle = "error";
161 return cont(endclosetag(err));
162 }
163 return cont();
164 }
165 function endtag(startOfLine) {
166 return function(type) {
167 if (type == "selfcloseTag" ||
168 (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
169 return cont();
170 if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
171 return cont();
172 };
173 }
174 function endclosetag(err) {
175 return function(type) {
176 if (err) setStyle = "error";
177 if (type == "endTag") { popContext(); return cont(); }
178 setStyle = "error";
179 return cont(arguments.callee);
180 }
181 }
182
183 function attributes(type) {
184 if (type == "word") {setStyle = "attribute"; return cont(attributes);}
185 if (type == "equals") return cont(attvalue, attributes);
186 if (type == "string") {setStyle = "error"; return cont(attributes);}
187 return pass();
188 }
189 function attvalue(type) {
190 if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
191 if (type == "string") return cont(attvaluemaybe);
192 return pass();
193 }
194 function attvaluemaybe(type) {
195 if (type == "string") return cont(attvaluemaybe);
196 else return pass();
197 }
198
199 return {
200 startState: function() {
201 return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
202 },
203
204 token: function(stream, state) {
205 if (stream.sol()) {
206 state.startOfLine = true;
207 state.indented = stream.indentation();
208 }
209 if (stream.eatSpace()) return null;
210
211 setStyle = type = tagName = null;
212 var style = state.tokenize(stream, state);
213 state.type = type;
214 if ((style || type) && style != "comment") {
215 curState = state;
216 while (true) {
217 var comb = state.cc.pop() || element;
218 if (comb(type || style)) break;
219 }
220 }
221 state.startOfLine = false;
222 return setStyle || style;
223 },
224
225 indent: function(state, textAfter, fullLine) {
226 var context = state.context;
227 if ((state.tokenize != inTag && state.tokenize != inText) ||
228 context && context.noIndent)
229 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
230 if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
231 if (context && /^<\//.test(textAfter))
232 context = context.prev;
233 while (context && !context.startOfLine)
234 context = context.prev;
235 if (context) return context.indent + indentUnit;
236 else return 0;
237 },
238
239 compareStates: function(a, b) {
240 if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
241 for (var ca = a.context, cb = b.contex