1 CodeMirror
.defineMode("htmlmixed", function(config
, parserConfig
) {
2 var htmlMode
= CodeMirror
.getMode(config
, {name
: "xml", htmlMode
: true});
3 var cssMode
= CodeMirror
.getMode(config
, "css");
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
)});
12 scriptTypes
.push({matches
: /./,
13 mode
: CodeMirror
.getMode(config
, "text/plain")});
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
)) {
28 state
.localMode
= tp
.mode
;
29 state
.localState
= tp
.mode
.startState
&& tp
.mode
.startState(htmlMode
.indent(state
.htmlState
, ""));
34 } else if (tagName
== "style" && /\btag\b/.test(style
) && stream
.current() == ">") {
36 state
.localMode
= cssMode
;
37 state
.localState
= cssMode
.startState(htmlMode
.indent(state
.htmlState
, ""));
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]);
51 function script(stream
, state
) {
52 if (stream
.match(/^<\/\s*script\s*>/i, false)) {
54 state
.localState
= state
.localMode
= null;
55 return html(stream
, state
);
57 return maybeBackup(stream
, /<\/\s*script\s*>/,
58 state
.localMode
.token(stream
, state
.localState
));
60 function css(stream
, state
) {
61 if (stream
.match(/^<\/\s*style\s*>/i, false)) {
63 state
.localState
= state
.localMode
= null;
64 return html(stream
, state
);
66 return maybeBackup(stream
, /<\/\s*style\s*>/,
67 cssMode
.token(stream
, state
.localState
));
71 startState: function() {
72 var state
= htmlMode
.startState();
73 return {token
: html
, localMode
: null, localState
: null, htmlState
: state
};
76 copyState: function(state
) {
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
)};
83 token: function(stream
, state
) {
84 return state
.token(stream
, state
);
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
);
93 return CodeMirror
.Pass
;
96 electricChars
: "/{}:",
98 innerMode: function(state
) {
99 return {state
: state
.localState
|| state
.htmlState
, mode
: state
.localMode
|| htmlMode
};
102 }, "xml", "javascript", "css");
104 CodeMirror
.defineMIME("text/html", "htmlmixed");