htmlmixed.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
  2. var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
  3. var cssMode = CodeMirror.getMode(config, "css");
  4. var scriptTypes = [], scriptTypesConf = parserConfig && parserConfig.scriptTypes;
  5. scriptTypes.push({matches: /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i,
  6. mode: CodeMirror.getMode(config, "javascript")});
  7. if (scriptTypesConf) for (var i = 0; i < scriptTypesConf.length; ++i) {
  8. var conf = scriptTypesConf[i];
  9. scriptTypes.push({matches: conf.matches, mode: conf.mode && CodeMirror.getMode(config, conf.mode)});
  10. }
  11. scriptTypes.push({matches: /./,
  12. mode: CodeMirror.getMode(config, "text/plain")});
  13. function html(stream, state) {
  14. var tagName = state.htmlState.tagName;
  15. var style = htmlMode.token(stream, state.htmlState);
  16. if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") {
  17. // Script block: mode to change to depends on type attribute
  18. var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i);
  19. scriptType = scriptType ? scriptType[1] : "";
  20. if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1);
  21. for (var i = 0; i < scriptTypes.length; ++i) {
  22. var tp = scriptTypes[i];
  23. if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) {
  24. if (tp.mode) {
  25. state.token = script;
  26. state.localMode = tp.mode;
  27. state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, ""));
  28. }
  29. break;
  30. }
  31. }
  32. } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") {
  33. state.token = css;
  34. state.localMode = cssMode;
  35. state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
  36. }
  37. return style;
  38. }
  39. function maybeBackup(stream, pat, style) {
  40. var cur = stream.current();
  41. var close = cur.search(pat), m;
  42. if (close > -1) stream.backUp(cur.length - close);
  43. else if (m = cur.match(/<\/?$/)) {
  44. stream.backUp(cur.length);
  45. if (!stream.match(pat, false)) stream.match(cur[0]);
  46. }
  47. return style;
  48. }
  49. function script(stream, state) {
  50. if (stream.match(/^<\/\s*script\s*>/i, false)) {
  51. state.token = html;
  52. state.localState = state.localMode = null;
  53. return html(stream, state);
  54. }
  55. return maybeBackup(stream, /<\/\s*script\s*>/,
  56. state.localMode.token(stream, state.localState));
  57. }
  58. function css(stream, state) {
  59. if (stream.match(/^<\/\s*style\s*>/i, false)) {
  60. state.token = html;
  61. state.localState = state.localMode = null;
  62. return html(stream, state);
  63. }
  64. return maybeBackup(stream, /<\/\s*style\s*>/,
  65. cssMode.token(stream, state.localState));
  66. }
  67. return {
  68. startState: function() {
  69. var state = htmlMode.startState();
  70. return {token: html, localMode: null, localState: null, htmlState: state};
  71. },
  72. copyState: function(state) {
  73. if (state.localState)
  74. var local = CodeMirror.copyState(state.localMode, state.localState);
  75. return {token: state.token, localMode: state.localMode, localState: local,
  76. htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
  77. },
  78. token: function(stream, state) {
  79. return state.token(stream, state);
  80. },
  81. indent: function(state, textAfter) {
  82. if (!state.localMode || /^\s*<\//.test(textAfter))
  83. return htmlMode.indent(state.htmlState, textAfter);
  84. else if (state.localMode.indent)
  85. return state.localMode.indent(state.localState, textAfter);
  86. else
  87. return CodeMirror.Pass;
  88. },
  89. electricChars: "/{}:",
  90. innerMode: function(state) {
  91. return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
  92. }
  93. };
  94. }, "xml", "javascript", "css");
  95. CodeMirror.defineMIME("text/html", "htmlmixed");