ec0c21d24ad8c198f84a06eaacc1f7e67023daca
[myslice.git] / third-party / codemirror-3.15 / mode / htmlmixed / htmlmixed.js
1 CodeMirror.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[0]);
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
104 CodeMirror.defineMIME("text/html", "htmlmixed");