aboutsummaryrefslogtreecommitdiff
path: root/js/codemirror/mode/xml
diff options
context:
space:
mode:
Diffstat (limited to 'js/codemirror/mode/xml')
-rw-r--r--js/codemirror/mode/xml/index.html42
-rw-r--r--js/codemirror/mode/xml/xml.js231
2 files changed, 273 insertions, 0 deletions
diff --git a/js/codemirror/mode/xml/index.html b/js/codemirror/mode/xml/index.html
new file mode 100644
index 00000000..122848ae
--- /dev/null
+++ b/js/codemirror/mode/xml/index.html
@@ -0,0 +1,42 @@
1<!doctype html>
2<html>
3 <head>
4 <title>CodeMirror 2: XML mode</title>
5 <link rel="stylesheet" href="../../lib/codemirror.css">
6 <script src="../../lib/codemirror.js"></script>
7 <script src="xml.js"></script>
8 <link rel="stylesheet" href="../../theme/default.css">
9 <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
10 <link rel="stylesheet" href="../../css/docs.css">
11 </head>
12 <body>
13 <h1>CodeMirror 2: XML mode</h1>
14 <form><textarea id="code" name="code">
15&lt;html style="color: green"&gt;
16 &lt;!-- this is a comment --&gt;
17 &lt;head&gt;
18 &lt;title&gt;HTML Example&lt;/title&gt;
19 &lt;/head&gt;
20 &lt;body&gt;
21 The indentation tries to be &lt;em&gt;somewhat &amp;quot;do what
22 I mean&amp;quot;&lt;/em&gt;... but might not match your style.
23 &lt;/body&gt;
24&lt;/html&gt;
25</textarea></form>
26 <script>
27 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: {name: "xml", htmlMode: true}});
28 </script>
29 <p>The XML mode supports two configuration parameters:</p>
30 <dl>
31 <dt><code>htmlMode (boolean)</code></dt>
32 <dd>This switches the mode to parse HTML instead of XML. This
33 means attributes do not have to be quoted, and some elements
34 (such as <code>br</code>) do not require a closing tag.</dd>
35 <dt><code>alignCDATA (boolean)</code></dt>
36 <dd>Setting this to true will force the opening tag of CDATA
37 blocks to not be indented.</dd>
38 </dl>
39
40 <p><strong>MIME types defined:</strong> <code>application/xml</code>, <code>text/html</code>.</p>
41 </body>
42</html>
diff --git a/js/codemirror/mode/xml/xml.js b/js/codemirror/mode/xml/xml.js
new file mode 100644
index 00000000..b992964b
--- /dev/null
+++ b/js/codemirror/mode/xml/xml.js
@@ -0,0 +1,231 @@
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, "!cdata": true},
7 allowUnquoted: true
8 } : {autoSelfClosers: {}, doNotIndent: {"!cdata": true}, 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(inBlock("meta", ">"));
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
106 var curState, setStyle;
107 function pass() {
108 for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
109 }
110 function cont() {
111 pass.apply(null, arguments);
112 return true;
113 }
114
115 function pushContext(tagName, startOfLine) {
116 var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
117 curState.context = {
118 prev: curState.context,
119 tagName: tagName,
120 indent: curState.indented,
121 startOfLine: startOfLine,
122 noIndent: noIndent
123 };
124 }
125 function popContext() {
126 if (curState.context) curState.context = curState.context.prev;
127 }
128
129 function element(type) {
130 if (type == "openTag") {curState.tagName = tagName; return cont(attributes, endtag(curState.startOfLine));}
131 else if (type == "closeTag") {
132 var err = false;
133 if (curState.context) {
134 err = curState.context.tagName != tagName;
135 popContext();
136 } else {
137 err = true;
138 }
139 if (err) setStyle = "error";
140 return cont(endclosetag(err));
141 }
142 else if (type == "string") {
143 if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
144 if (curState.tokenize == inText) popContext();
145 return cont();
146 }
147 else return cont();
148 }
149 function endtag(startOfLine) {
150 return function(type) {
151 if (type == "selfcloseTag" ||
152 (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
153 return cont();
154 if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
155 return cont();
156 };
157 }
158 function endclosetag(err) {
159 return function(type) {
160 if (err) setStyle = "error";
161 if (type == "endTag") return cont();
162 return pass();
163 }
164 }
165
166 function attributes(type) {
167 if (type == "word") {setStyle = "attribute"; return cont(attributes);}
168 if (type == "equals") return cont(attvalue, attributes);
169 return pass();
170 }
171 function attvalue(type) {
172 if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
173 if (type == "string") return cont(attvaluemaybe);
174 return pass();
175 }
176 function attvaluemaybe(type) {
177 if (type == "string") return cont(attvaluemaybe);
178 else return pass();
179 }
180
181 return {
182 startState: function() {
183 return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
184 },
185
186 token: function(stream, state) {
187 if (stream.sol()) {
188 state.startOfLine = true;
189 state.indented = stream.indentation();
190 }
191 if (stream.eatSpace()) return null;
192
193 setStyle = type = tagName = null;
194 var style = state.tokenize(stream, state);
195 if