Index: branches/5.3.x/core/admin_templates/incs/code_mirror/mode/htmlmixed/htmlmixed.js =================================================================== diff -u -N -r15690 -r15914 --- branches/5.3.x/core/admin_templates/incs/code_mirror/mode/htmlmixed/htmlmixed.js (.../htmlmixed.js) (revision 15690) +++ branches/5.3.x/core/admin_templates/incs/code_mirror/mode/htmlmixed/htmlmixed.js (.../htmlmixed.js) (revision 15914) @@ -1,19 +1,40 @@ -CodeMirror.defineMode("htmlmixed", function(config) { +CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true}); - var jsMode = CodeMirror.getMode(config, "javascript"); var cssMode = CodeMirror.getMode(config, "css"); + var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes; + scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, + mode: CodeMirror.getMode(config, "javascript")}); + if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) { + var conf = scriptTypesConf[i]; + scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)}); + } + scriptTypes.push({matches: /./, + mode: CodeMirror.getMode(config, "text/plain")}); + function html(stream, state) { + var tagName = state.htmlState.tagName; var style = htmlMode.token(stream, state.htmlState); - if (/(?:^|\s)tag(?:\s|$)/.test(style) && stream.current() == ">" && state.htmlState.context) { - if (/^script$/i.test(state.htmlState.context.tagName)) { - state.token = javascript; - state.localState = jsMode.startState(htmlMode.indent(state.htmlState, "")); + if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") { + // Script block: mode to change to depends on type attribute + var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); + scriptType = scriptType ? scriptType[1] : ""; + if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); + for (var i = 0; i < scriptTypes.length; ++i) { + var tp = scriptTypes[i]; + if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { + if (tp.mode) { + state.token = script; + state.localMode = tp.mode; + state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); + } + break; + } } - else if (/^style$/i.test(state.htmlState.context.tagName)) { - state.token = css; - state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); - } + } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") { + state.token = css; + state.localMode = cssMode; + state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); } return style; } @@ -27,19 +48,19 @@ } return style; } - function javascript(stream, state) { + function script(stream, state) { if (stream.match(/^<\/\s*script\s*>/i, false)) { state.token = html; - state.localState = null; + state.localState = state.localMode = null; return html(stream, state); } return maybeBackup(stream, /<\/\s*script\s*>/, - jsMode.token(stream, state.localState)); + state.localMode.token(stream, state.localState)); } function css(stream, state) { if (stream.match(/^<\/\s*style\s*>/i, false)) { state.token = html; - state.localState = null; + state.localState = state.localMode = null; return html(stream, state); } return maybeBackup(stream, /<\/\s*style\s*>/, @@ -49,13 +70,13 @@ return { startState: function() { var state = htmlMode.startState(); - return {token: html, localState: null, mode: "html", htmlState: state}; + return {token: html, localMode: null, localState: null, htmlState: state}; }, copyState: function(state) { if (state.localState) - var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState); - return {token: state.token, localState: local, mode: state.mode, + var local = CodeMirror.copyState(state.localMode, state.localState); + return {token: state.token, localMode: state.localMode, localState: local, htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; }, @@ -64,19 +85,18 @@ }, indent: function(state, textAfter) { - if (state.token == html || /^\s*<\//.test(textAfter)) + if (!state.localMode || /^\s*<\//.test(textAfter)) return htmlMode.indent(state.htmlState, textAfter); - else if (state.token == javascript) - return jsMode.indent(state.localState, textAfter); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter); else - return cssMode.indent(state.localState, textAfter); + return CodeMirror.Pass; }, electricChars: "/{}:", innerMode: function(state) { - var mode = state.token == html ? htmlMode : state.token == javascript ? jsMode : cssMode; - return {state: state.localState || state.htmlState, mode: mode}; + return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; } }; }, "xml", "javascript", "css");