Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 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
CodeMirror.defineMode("xml", function(config, parserConfig) {
15
  var indentUnit = config.indentUnit;
16
  var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
17
  var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
18
  if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
19
 
20
  var Kludges = parserConfig.htmlMode ? {
21
    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
22
                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
23
                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
24
                      'track': true, 'wbr': true, 'menuitem': true},
25
    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
26
                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
27
                       'th': true, 'tr': true},
28
    contextGrabbers: {
29
      'dd': {'dd': true, 'dt': true},
30
      'dt': {'dd': true, 'dt': true},
31
      'li': {'li': true},
32
      'option': {'option': true, 'optgroup': true},
33
      'optgroup': {'optgroup': true},
34
      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
35
            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
36
            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
37
            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
38
            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
39
      'rp': {'rp': true, 'rt': true},
40
      'rt': {'rp': true, 'rt': true},
41
      'tbody': {'tbody': true, 'tfoot': true},
42
      'td': {'td': true, 'th': true},
43
      'tfoot': {'tbody': true},
44
      'th': {'td': true, 'th': true},
45
      'thead': {'tbody': true, 'tfoot': true},
46
      'tr': {'tr': true}
47
    },
48
    doNotIndent: {"pre": true},
49
    allowUnquoted: true,
50
    allowMissing: true,
51
    caseFold: true
52
  } : {
53
    autoSelfClosers: {},
54
    implicitlyClosed: {},
55
    contextGrabbers: {},
56
    doNotIndent: {},
57
    allowUnquoted: false,
58
    allowMissing: false,
59
    caseFold: false
60
  };
61
  var alignCDATA = parserConfig.alignCDATA;
62
 
63
  // Return variables for tokenizers
64
  var type, setStyle;
65
 
66
  function inText(stream, state) {
67
    function chain(parser) {
68
      state.tokenize = parser;
69
      return parser(stream, state);
70
    }
71
 
72
    var ch = stream.next();
73
    if (ch == "<") {
74
      if (stream.eat("!")) {
75
        if (stream.eat("[")) {
76
          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
77
          else return null;
78
        } else if (stream.match("--")) {
79
          return chain(inBlock("comment", "-->"));
80
        } else if (stream.match("DOCTYPE", true, true)) {
81
          stream.eatWhile(/[\w\._\-]/);
82
          return chain(doctype(1));
83
        } else {
84
          return null;
85
        }
86
      } else if (stream.eat("?")) {
87
        stream.eatWhile(/[\w\._\-]/);
88
        state.tokenize = inBlock("meta", "?>");
89
        return "meta";
90
      } else {
91
        type = stream.eat("/") ? "closeTag" : "openTag";
92
        state.tokenize = inTag;
93
        return "tag bracket";
94
      }
95
    } else if (ch == "&") {
96
      var ok;
97
      if (stream.eat("#")) {
98
        if (stream.eat("x")) {
99
          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
100
        } else {
101
          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
102
        }
103
      } else {
104
        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
105
      }
106
      return ok ? "atom" : "error";
107
    } else {
108
      stream.eatWhile(/[^&<]/);
109
      return null;
110
    }
111
  }
112
  inText.isInText = true;
113
 
114
  function inTag(stream, state) {
115
    var ch = stream.next();
116
    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
117
      state.tokenize = inText;
118
      type = ch == ">" ? "endTag" : "selfcloseTag";
119
      return "tag bracket";
120
    } else if (ch == "=") {
121
      type = "equals";
122
      return null;
123
    } else if (ch == "<") {
124
      state.tokenize = inText;
125
      state.state = baseState;
126
      state.tagName = state.tagStart = null;
127
      var next = state.tokenize(stream, state);
128
      return next ? next + " tag error" : "tag error";
129
    } else if (/[\'\"]/.test(ch)) {
130
      state.tokenize = inAttribute(ch);
131
      state.stringStartCol = stream.column();
132
      return state.tokenize(stream, state);
133
    } else {
134
      stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
135
      return "word";
136
    }
137
  }
138
 
139
  function inAttribute(quote) {
140
    var closure = function(stream, state) {
141
      while (!stream.eol()) {
142
        if (stream.next() == quote) {
143
          state.tokenize = inTag;
144
          break;
145
        }
146
      }
147
      return "string";
148
    };
149
    closure.isInAttribute = true;
150
    return closure;
151
  }
152
 
153
  function inBlock(style, terminator) {
154
    return function(stream, state) {
155
      while (!stream.eol()) {
156
        if (stream.match(terminator)) {
157
          state.tokenize = inText;
158
          break;
159
        }
160
        stream.next();
161
      }
162
      return style;
163
    };
164
  }
165
  function doctype(depth) {
166
    return function(stream, state) {
167
      var ch;
168
      while ((ch = stream.next()) != null) {
169
        if (ch == "<") {
170
          state.tokenize = doctype(depth + 1);
171
          return state.tokenize(stream, state);
172
        } else if (ch == ">") {
173
          if (depth == 1) {
174
            state.tokenize = inText;
175
            break;
176
          } else {
177
            state.tokenize = doctype(depth - 1);
178
            return state.tokenize(stream, state);
179
          }
180
        }
181
      }
182
      return "meta";
183
    };
184
  }
185
 
186
  function Context(state, tagName, startOfLine) {
187
    this.prev = state.context;
188
    this.tagName = tagName;
189
    this.indent = state.indented;
190
    this.startOfLine = startOfLine;
191
    if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
192
      this.noIndent = true;
193
  }
194
  function popContext(state) {
195
    if (state.context) state.context = state.context.prev;
196
  }
197
  function maybePopContext(state, nextTagName) {
198
    var parentTagName;
199
    while (true) {
200
      if (!state.context) {
201
        return;
202
      }
203
      parentTagName = state.context.tagName;
204
      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
205
          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
206
        return;
207
      }
208
      popContext(state);
209
    }
210
  }
211
 
212
  function baseState(type, stream, state) {
213
    if (type == "openTag") {
214
      state.tagStart = stream.column();
215
      return tagNameState;
216
    } else if (type == "closeTag") {
217
      return closeTagNameState;
218
    } else {
219
      return baseState;
220
    }
221
  }
222
  function tagNameState(type, stream, state) {
223
    if (type == "word") {
224
      state.tagName = stream.current();
225
      setStyle = "tag";
226
      return attrState;
227
    } else {
228
      setStyle = "error";
229
      return tagNameState;
230
    }
231
  }
232
  function closeTagNameState(type, stream, state) {
233
    if (type == "word") {
234
      var tagName = stream.current();
235
      if (state.context && state.context.tagName != tagName &&
236
          Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
237
        popContext(state);
238
      if (state.context && state.context.tagName == tagName) {
239
        setStyle = "tag";
240
        return closeState;
241
      } else {
242
        setStyle = "tag error";
243
        return closeStateErr;
244
      }
245
    } else {
246
      setStyle = "error";
247
      return closeStateErr;
248
    }
249
  }
250
 
251
  function closeState(type, _stream, state) {
252
    if (type != "endTag") {
253
      setStyle = "error";
254
      return closeState;
255
    }
256
    popContext(state);
257
    return baseState;
258
  }
259
  function closeStateErr(type, stream, state) {
260
    setStyle = "error";
261
    return closeState(type, stream, state);
262
  }
263
 
264
  function attrState(type, _stream, state) {
265
    if (type == "word") {
266
      setStyle = "attribute";
267
      return attrEqState;
268
    } else if (type == "endTag" || type == "selfcloseTag") {
269
      var tagName = state.tagName, tagStart = state.tagStart;
270
      state.tagName = state.tagStart = null;
271
      if (type == "selfcloseTag" ||
272
          Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
273
        maybePopContext(state, tagName);
274
      } else {
275
        maybePopContext(state, tagName);
276
        state.context = new Context(state, tagName, tagStart == state.indented);
277
      }
278
      return baseState;
279
    }
280
    setStyle = "error";
281
    return attrState;
282
  }
283
  function attrEqState(type, stream, state) {
284
    if (type == "equals") return attrValueState;
285
    if (!Kludges.allowMissing) setStyle = "error";
286
    return attrState(type, stream, state);
287
  }
288
  function attrValueState(type, stream, state) {
289
    if (type == "string") return attrContinuedState;
290
    if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
291
    setStyle = "error";
292
    return attrState(type, stream, state);
293
  }
294
  function attrContinuedState(type, stream, state) {
295
    if (type == "string") return attrContinuedState;
296
    return attrState(type, stream, state);
297
  }
298
 
299
  return {
300
    startState: function() {
301
      return {tokenize: inText,
302
              state: baseState,
303
              indented: 0,
304
              tagName: null, tagStart: null,
305
              context: null};
306
    },
307
 
308
    token: function(stream, state) {
309
      if (!state.tagName && stream.sol())
310
        state.indented = stream.indentation();
311
 
312
      if (stream.eatSpace()) return null;
313
      type = null;
314
      var style = state.tokenize(stream, state);
315
      if ((style || type) && style != "comment") {
316
        setStyle = null;
317
        state.state = state.state(type || style, stream, state);
318
        if (setStyle)
319
          style = setStyle == "error" ? style + " error" : setStyle;
320
      }
321
      return style;
322
    },
323
 
324
    indent: function(state, textAfter, fullLine) {
325
      var context = state.context;
326
      // Indent multi-line strings (e.g. css).
327
      if (state.tokenize.isInAttribute) {
328
        if (state.tagStart == state.indented)
329
          return state.stringStartCol + 1;
330
        else
331
          return state.indented + indentUnit;
332
      }
333
      if (context && context.noIndent) return CodeMirror.Pass;
334
      if (state.tokenize != inTag && state.tokenize != inText)
335
        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
336
      // Indent the starts of attribute names.
337
      if (state.tagName) {
338
        if (multilineTagIndentPastTag)
339
          return state.tagStart + state.tagName.length + 2;
340
        else
341
          return state.tagStart + indentUnit * multilineTagIndentFactor;
342
      }
343
      if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
344
      var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
345
      if (tagAfter && tagAfter[1]) { // Closing tag spotted
346
        while (context) {
347
          if (context.tagName == tagAfter[2]) {
348
            context = context.prev;
349
            break;
350
          } else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
351
            context = context.prev;
352
          } else {
353
            break;
354
          }
355
        }
356
      } else if (tagAfter) { // Opening tag spotted
357
        while (context) {
358
          var grabbers = Kludges.contextGrabbers[context.tagName];
359
          if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
360
            context = context.prev;
361
          else
362
            break;
363
        }
364
      }
365
      while (context && !context.startOfLine)
366
        context = context.prev;
367
      if (context) return context.indent + indentUnit;
368
      else return 0;
369
    },
370
 
371
    electricInput: /<\/[\s\w:]+>$/,
372
    blockCommentStart: "<!--",
373
    blockCommentEnd: "-->",
374
 
375
    configuration: parserConfig.htmlMode ? "html" : "xml",
376
    helperType: parserConfig.htmlMode ? "html" : "xml"
377
  };
378
});
379
 
380
CodeMirror.defineMIME("text/xml", "xml");
381
CodeMirror.defineMIME("application/xml", "xml");
382
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
383
  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
384
 
385
});