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