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