• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
2  var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
3  var cssMode = CodeMirror.getMode(config, "css");
4
5  var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
6  scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
7                    mode: CodeMirror.getMode(config, "javascript")});
8  if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
9    var conf = scriptTypesConf[i];
10    scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
11  }
12  scriptTypes.push({matches: /./,
13                    mode: CodeMirror.getMode(config, "text/plain")});
14
15  function html(stream, state) {
16    var tagName = state.htmlState.tagName;
17    var style = htmlMode.token(stream, state.htmlState);
18    if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
19      // Script block: mode to change to depends on type attribute
20      var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
21      scriptType = scriptType ? scriptType[1] : "";
22      if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
23      for (var i = 0; i < scriptTypes.length; ++i) {
24        var tp = scriptTypes[i];
25        if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
26          if (tp.mode) {
27            state.token = script;
28            state.localMode = tp.mode;
29            state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
30          }
31          break;
32        }
33      }
34    } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
35      state.token = css;
36      state.localMode = cssMode;
37      state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
38    }
39    return style;
40  }
41  function maybeBackup(stream, pat, style) {
42    var cur = stream.current();
43    var close = cur.search(pat), m;
44    if (close > -1) stream.backUp(cur.length - close);
45    else if (m = cur.match(/<\/?$/)) {
46      stream.backUp(cur.length);
47      if (!stream.match(pat, false)) stream.match(cur);
48    }
49    return style;
50  }
51  function script(stream, state) {
52    if (stream.match(/^<\/\s*script\s*>/i, false)) {
53      state.token = html;
54      state.localState = state.localMode = null;
55      return html(stream, state);
56    }
57    return maybeBackup(stream, /<\/\s*script\s*>/,
58                       state.localMode.token(stream, state.localState));
59  }
60  function css(stream, state) {
61    if (stream.match(/^<\/\s*style\s*>/i, false)) {
62      state.token = html;
63      state.localState = state.localMode = null;
64      return html(stream, state);
65    }
66    return maybeBackup(stream, /<\/\s*style\s*>/,
67                       cssMode.token(stream, state.localState));
68  }
69
70  return {
71    startState: function() {
72      var state = htmlMode.startState();
73      return {token: html, localMode: null, localState: null, htmlState: state};
74    },
75
76    copyState: function(state) {
77      if (state.localState)
78        var local = CodeMirror.copyState(state.localMode, state.localState);
79      return {token: state.token, localMode: state.localMode, localState: local,
80              htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
81    },
82
83    token: function(stream, state) {
84      return state.token(stream, state);
85    },
86
87    indent: function(state, textAfter) {
88      if (!state.localMode || /^\s*<\//.test(textAfter))
89        return htmlMode.indent(state.htmlState, textAfter);
90      else if (state.localMode.indent)
91        return state.localMode.indent(state.localState, textAfter);
92      else
93        return CodeMirror.Pass;
94    },
95
96    electricChars: "/{}:",
97
98    innerMode: function(state) {
99      return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
100    }
101  };
102}, "xml", "javascript", "css");
103
104CodeMirror.defineMIME("text/html", "htmlmixed");
105