|
| 1 | +(function() { |
| 2 | + function keywords(str) { |
| 3 | + var obj = {}, words = str.split(" "); |
| 4 | + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; |
| 5 | + return obj; |
| 6 | + } |
| 7 | + var phpKeywords = |
| 8 | + keywords("abstract and array as break case catch cfunction class clone const continue declare " + |
| 9 | + "default do else elseif enddeclare endfor endforeach endif endswitch endwhile extends " + |
| 10 | + "final for foreach function global goto if implements interface instanceof namespace " + |
| 11 | + "new or private protected public static switch throw try use var while xor"); |
| 12 | + |
| 13 | + CodeMirror.defineMode("php", function(config, parserConfig) { |
| 14 | + var htmlMode = CodeMirror.getMode(config, "text/html"); |
| 15 | + var jsMode = CodeMirror.getMode(config, "text/javascript"); |
| 16 | + var cssMode = CodeMirror.getMode(config, "text/css"); |
| 17 | + var phpMode = CodeMirror.getMode(config, {name: "clike", keywords: phpKeywords}); |
| 18 | + |
| 19 | + function dispatch(stream, state) { // TODO open PHP inside text/css |
| 20 | + var cur = state.context[0]; |
| 21 | + if (cur.mode == htmlMode) { |
| 22 | + var style = htmlMode.token(stream, cur.state); |
| 23 | + if (style == "xml-processing") |
| 24 | + state.context.unshift({mode: phpMode, state: state.php, close: /^\?>/}); |
| 25 | + else if (style == "xml-tag" && stream.current() == ">" && cur.state.context) { |
| 26 | + if (/^script$/i.test(cur.state.context.tagName)) |
| 27 | + state.context.unshift({mode: jsMode, |
| 28 | + state: jsMode.startState(htmlMode.indent(cur.state, "")), |
| 29 | + close: /^<\/\s*script\s*>/i}); |
| 30 | + else if (/^style$/i.test(cur.state.context.tagName)) |
| 31 | + state.context.unshift({mode: cssMode, |
| 32 | + state: cssMode.startState(htmlMode.indent(cur.state, "")), |
| 33 | + close: /^<\/\s*style\s*>/i}); |
| 34 | + } |
| 35 | + return style; |
| 36 | + } |
| 37 | + else if (stream.match(cur.close, false)) { |
| 38 | + state.context.shift(); |
| 39 | + return dispatch(stream, state); |
| 40 | + } |
| 41 | + else return cur.mode.token(stream, cur.state); |
| 42 | + } |
| 43 | + |
| 44 | + return { |
| 45 | + startState: function() { |
| 46 | + var html = htmlMode.startState(); |
| 47 | + return {html: html, |
| 48 | + php: phpMode.startState(), |
| 49 | + context: [{mode: htmlMode, state: html, close: null}]}; |
| 50 | + }, |
| 51 | + |
| 52 | + copyState: function(state) { |
| 53 | + var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html), |
| 54 | + php = state.php, phpNew = CodeMirror.copyState(phpMode, php), contextNew = []; |
| 55 | + for (var i = 0; i < state.context.length; ++i) { |
| 56 | + var context = state.context[i], cstate = context.state; |
| 57 | + if (cstate == html) cstate = htmlNew; |
| 58 | + else if (cstate == php) cstate = phpNew; |
| 59 | + else cstate = CodeMirror.copyState(context.mode, cstate); |
| 60 | + contextNew.push({mode: context.mode, state: cstate, close: context.close}); |
| 61 | + } |
| 62 | + return {html: htmlNew, php: phpNew, context: contextNew}; |
| 63 | + }, |
| 64 | + |
| 65 | + token: dispatch, |
| 66 | + |
| 67 | + indent: function(state, textAfter) { |
| 68 | + var cur = state.context[0]; |
| 69 | + return cur.mode.indent(cur.state, textAfter); |
| 70 | + }, |
| 71 | + |
| 72 | + electricChars: "/{}:" |
| 73 | + } |
| 74 | + }); |
| 75 | +})(); |
| 76 | + |
| 77 | +CodeMirror.defineMIME("application/x-httpd-php", "php"); |
0 commit comments