1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
5 if (typeof exports
== "object" && typeof module
== "object") // CommonJS
6 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
7 else if (typeof define
== "function" && define
.amd
) // AMD
8 define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod
);
9 else // Plain browser env
11 })(function(CodeMirror
) {
14 CodeMirror
.defineMode("htmlmixed", function(config
, parserConfig
) {
15 var htmlMode
= CodeMirror
.getMode(config
, {name
: "xml",
17 multilineTagIndentFactor
: parserConfig
.multilineTagIndentFactor
,
18 multilineTagIndentPastTag
: parserConfig
.multilineTagIndentPastTag
});
19 var cssMode
= CodeMirror
.getMode(config
, "css");
21 var scriptTypes
= [], scriptTypesConf
= parserConfig
&& parserConfig
.scriptTypes
;
22 scriptTypes
.push({matches
: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
23 mode
: CodeMirror
.getMode(config
, "javascript")});
24 if (scriptTypesConf
) for (var i
= 0; i
< scriptTypesConf
.length
; ++i
) {
25 var conf
= scriptTypesConf
[i
];
26 scriptTypes
.push({matches
: conf
.matches
, mode
: conf
.mode
&& CodeMirror
.getMode(config
, conf
.mode
)});
28 scriptTypes
.push({matches
: /./,
29 mode
: CodeMirror
.getMode(config
, "text/plain")});
31 function html(stream
, state
) {
32 var tagName
= state
.htmlState
.tagName
;
33 if (tagName
) tagName
= tagName
.toLowerCase();
34 var style
= htmlMode
.token(stream
, state
.htmlState
);
35 if (tagName
== "script" && /\btag\b/.test(style
) && stream
.current() == ">") {
36 // Script block: mode to change to depends on type attribute
37 var scriptType
= stream
.string
.slice(Math
.max(0, stream
.pos
- 100), stream
.pos
).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
38 scriptType
= scriptType
? scriptType
[1] : "";
39 if (scriptType
&& /[\"\']/.test(scriptType
.charAt(0))) scriptType
= scriptType
.slice(1, scriptType
.length
- 1);
40 for (var i
= 0; i
< scriptTypes
.length
; ++i
) {
41 var tp
= scriptTypes
[i
];
42 if (typeof tp
.matches
== "string" ? scriptType
== tp
.matches
: tp
.matches
.test(scriptType
)) {
45 state
.localMode
= tp
.mode
;
46 state
.localState
= tp
.mode
.startState
&& tp
.mode
.startState(htmlMode
.indent(state
.htmlState
, ""));
51 } else if (tagName
== "style" && /\btag\b/.test(style
) && stream
.current() == ">") {
53 state
.localMode
= cssMode
;
54 state
.localState
= cssMode
.startState(htmlMode
.indent(state
.htmlState
, ""));
58 function maybeBackup(stream
, pat
, style
) {
59 var cur
= stream
.current();
60 var close
= cur
.search(pat
), m
;
61 if (close
> -1) stream
.backUp(cur
.length
- close
);
62 else if (m
= cur
.match(/<\/?$/)) {
63 stream
.backUp(cur
.length
);
64 if (!stream
.match(pat
, false)) stream
.match(cur
);
68 function script(stream
, state
) {
69 if (stream
.match(/^<\/\s*script\s*>/i, false)) {
71 state
.localState
= state
.localMode
= null;
72 return html(stream
, state
);
74 return maybeBackup(stream
, /<\/\s*script\s*>/,
75 state
.localMode
.token(stream
, state
.localState
));
77 function css(stream
, state
) {
78 if (stream
.match(/^<\/\s*style\s*>/i, false)) {
80 state
.localState
= state
.localMode
= null;
81 return html(stream
, state
);
83 return maybeBackup(stream
, /<\/\s*style\s*>/,
84 cssMode
.token(stream
, state
.localState
));
88 startState: function() {
89 var state
= htmlMode
.startState();
90 return {token
: html
, localMode
: null, localState
: null, htmlState
: state
};
93 copyState: function(state
) {
95 var local
= CodeMirror
.copyState(state
.localMode
, state
.localState
);
96 return {token
: state
.token
, localMode
: state
.localMode
, localState
: local
,
97 htmlState
: CodeMirror
.copyState(htmlMode
, state
.htmlState
)};
100 token: function(stream
, state
) {
101 return state
.token(stream
, state
);
104 indent: function(state
, textAfter
) {
105 if (!state
.localMode
|| /^\s*<\//.test(textAfter
))
106 return htmlMode
.indent(state
.htmlState
, textAfter
);
107 else if (state
.localMode
.indent
)
108 return state
.localMode
.indent(state
.localState
, textAfter
);
110 return CodeMirror
.Pass
;
113 innerMode: function(state
) {
114 return {state
: state
.localState
|| state
.htmlState
, mode
: state
.localMode
|| htmlMode
};
117 }, "xml", "javascript", "css");
119 CodeMirror
.defineMIME("text/html", "htmlmixed");