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