michael@0: (function(mod) { michael@0: if (typeof exports == "object" && typeof module == "object") // CommonJS michael@0: mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); michael@0: else if (typeof define == "function" && define.amd) // AMD michael@0: define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); michael@0: else // Plain browser env michael@0: mod(CodeMirror); michael@0: })(function(CodeMirror) { michael@0: "use strict"; michael@0: michael@0: CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { michael@0: var htmlMode = CodeMirror.getMode(config, {name: "xml", michael@0: htmlMode: true, michael@0: multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, michael@0: multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag}); michael@0: var cssMode = CodeMirror.getMode(config, "css"); michael@0: michael@0: var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes; michael@0: scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, michael@0: mode: CodeMirror.getMode(config, "javascript")}); michael@0: if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) { michael@0: var conf = scriptTypesConf[i]; michael@0: scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)}); michael@0: } michael@0: scriptTypes.push({matches: /./, michael@0: mode: CodeMirror.getMode(config, "text/plain")}); michael@0: michael@0: function html(stream, state) { michael@0: var tagName = state.htmlState.tagName; michael@0: var style = htmlMode.token(stream, state.htmlState); michael@0: if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") { michael@0: // Script block: mode to change to depends on type attribute michael@0: var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); michael@0: scriptType = scriptType ? scriptType[1] : ""; michael@0: if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); michael@0: for (var i = 0; i < scriptTypes.length; ++i) { michael@0: var tp = scriptTypes[i]; michael@0: if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { michael@0: if (tp.mode) { michael@0: state.token = script; michael@0: state.localMode = tp.mode; michael@0: state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") { michael@0: state.token = css; michael@0: state.localMode = cssMode; michael@0: state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); michael@0: } michael@0: return style; michael@0: } michael@0: function maybeBackup(stream, pat, style) { michael@0: var cur = stream.current(); michael@0: var close = cur.search(pat), m; michael@0: if (close > -1) stream.backUp(cur.length - close); michael@0: else if (m = cur.match(/<\/?$/)) { michael@0: stream.backUp(cur.length); michael@0: if (!stream.match(pat, false)) stream.match(cur); michael@0: } michael@0: return style; michael@0: } michael@0: function script(stream, state) { michael@0: if (stream.match(/^<\/\s*script\s*>/i, false)) { michael@0: state.token = html; michael@0: state.localState = state.localMode = null; michael@0: return html(stream, state); michael@0: } michael@0: return maybeBackup(stream, /<\/\s*script\s*>/, michael@0: state.localMode.token(stream, state.localState)); michael@0: } michael@0: function css(stream, state) { michael@0: if (stream.match(/^<\/\s*style\s*>/i, false)) { michael@0: state.token = html; michael@0: state.localState = state.localMode = null; michael@0: return html(stream, state); michael@0: } michael@0: return maybeBackup(stream, /<\/\s*style\s*>/, michael@0: cssMode.token(stream, state.localState)); michael@0: } michael@0: michael@0: return { michael@0: startState: function() { michael@0: var state = htmlMode.startState(); michael@0: return {token: html, localMode: null, localState: null, htmlState: state}; michael@0: }, michael@0: michael@0: copyState: function(state) { michael@0: if (state.localState) michael@0: var local = CodeMirror.copyState(state.localMode, state.localState); michael@0: return {token: state.token, localMode: state.localMode, localState: local, michael@0: htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; michael@0: }, michael@0: michael@0: token: function(stream, state) { michael@0: return state.token(stream, state); michael@0: }, michael@0: michael@0: indent: function(state, textAfter) { michael@0: if (!state.localMode || /^\s*<\//.test(textAfter)) michael@0: return htmlMode.indent(state.htmlState, textAfter); michael@0: else if (state.localMode.indent) michael@0: return state.localMode.indent(state.localState, textAfter); michael@0: else michael@0: return CodeMirror.Pass; michael@0: }, michael@0: michael@0: innerMode: function(state) { michael@0: return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; michael@0: } michael@0: }; michael@0: }, "xml", "javascript", "css"); michael@0: michael@0: CodeMirror.defineMIME("text/html", "htmlmixed"); michael@0: michael@0: });