CodeMirror syntax highlighting support for TinyMCE

The TinyMCE Javascript WYSIWYG widget has become the industry-standard plugin due to its stability and customizability. The one thing it’s missing, in my opinion, is syntax-highlighting in the code editor. A few people have tried integrating CodePress or CodeMirror into plugins but nothing has really taken off. So for now I just hacked the existing TinyMCE HTML editor to add CodeMirror support (which gives, in particular, a text wrapping option which CodePress does not). A TinyMCE developer would no doubt be able to convert this into a clean plugin, but this works for now.

Steps (the following are for TinyMCE version 3.3.9.2):

1) Hack /themes/advanced/source_editor.html in the HEAD tag to add a reference to the codemirror script, in my case to /js/codemirror/, as well as a few minor styles to make it prettier.

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3. 	<title>{#advanced_dlg.code_title}</title>
  4. 	<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
  5. 	<script type="text/javascript" src="js/source_editor.js"></script>
  6.     <script type="text/javascript" src="/js/codemirror/js/codemirror.js"></script>
  7.     <style type="text/css">
  8.         div.CodeMirror-wrapping { background-color: #fff; border: 1px solid #ccc }
  9.         div.CodeMirror-line-numbers {
  10.             width: 2.2em;
  11.             color: #aaa;
  12.             background-color: #eee;
  13.             text-align: right;
  14.             padding-right: .3em;
  15.             font-size: 10pt;
  16.             font-family: monospace;
  17.             padding-top: .4em;
  18.         }
  19.     </style>
  20. </head>
  21. ...

2) Hack /themes/advanced/js/source_editor.js to use CodeMirror:

  1. tinyMCEPopup.requireLangPack();
  2. tinyMCEPopup.onInit.add(onLoadInit);
  3.  
  4. var editor;
  5.  
  6. function saveContent() {
  7. tinyMCEPopup.editor.setContent(editor.getCode());
  8. tinyMCEPopup.close();
  9. }
  10.  
  11. function onLoadInit() {
  12. tinyMCEPopup.resizeToInnerSize();
  13.  
  14. // Remove Gecko spellchecking
  15. if (tinymce.isGecko)
  16. document.body.spellcheck = tinyMCEPopup.editor.getParam("gecko_spellcheck");
  17.  
  18. document.getElementById('htmlSource').value = tinyMCEPopup.editor.getContent({ source_view: true });
  19.  
  20. if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) {
  21. document.getElementById('wraped').checked = true;
  22. }
  23.  
  24. resizeInputs();
  25.  
  26. editor = CodeMirror.fromTextArea('htmlSource', {
  27. path: '/js/codemirror/js/',
  28. parserfile: ["parsexml.js"],
  29. stylesheet: "/js/codemirror/css/xmlcolors.css",
  30. textWrapping: true,
  31. lineNumbers: true
  32. });
  33. }
  34.  
  35. function toggleWordWrap(elm) {
  36. editor.setTextWrapping(elm.checked);
  37. }
  38.  
  39. function resizeInputs() {
  40.  
  41. var vp = tinyMCEPopup.dom.getViewPort(window), el;
  42.  
  43. el = document.getElementById('htmlSource');
  44.  
  45. if (el) {
  46. el.style.width  = (vp.w - 20) + 'px';
  47. el.style.height = (vp.h - 65) + 'px';
  48. }
  49.  
  50. }

3) Copy the codemirror directory, in my case, to /js/codemirror/.

Instantiate TinyMCE as usual; now when you click the HTML button you’ll get CodeMirror HTML syntax highlighting.

4 comments

  1. I tried this and it works except when you click Update, nothing happens.
    TinyMCE version 3.3.9.3
    CodeMirror version 0.94

    Any ideas?

    Thanks

  2. Jim- What do you mean by clicking “Update” – there’s no update button in the widget. Sounds like you have a Javascript error somewhere, check the debugger and see what’s going on.

  3. Thanks, this was extremely helpful.

    I have an answer to Jim’s question (I had the same problem). I’m using CodeMirror 2. Here’s how I solved it:

    In source_editor.js

    Changed the saveContent function from this:

    function saveContent() {
    tinyMCEPopup.editor.setContent(document.getElementById(‘htmlSource’).value, {source_view : true});
    tinyMCEPopup.close();
    }

    to this:

    function saveContent() {
    tinyMCEPopup.editor.setContent(editor.getValue(), {source_view : true});
    tinyMCEPopup.close();
    }

    That makes tinyMCE use the CodeMirror content when you press the “update” button in the lower left of the pop-up code-editor window.

    Also, I think the initialization of CodeMirror2 is different than you have here. In the onLoadInit function, I used this to set the “editor” variable:

    editor = CodeMirror.fromTextArea(document.getElementById(‘htmlSource’), {
    mode: “text/html”,
    tabMode: “indent”,
    enterMode: “keep”
    });

    I also added more CSS and JS includes in the source_editor.htm file:

    {#v1_dlg.code_title}

    // copied the css/js files that were included in this example:
    // codemirror/mode/htmlmixed/index.html

    .CodeMirror { height:510px; background:white; margin-top:5px; font-size:12px; line-height:18px; font-family:Monaco, Courier, monospace; }
    .CodeMirror-lines { padding:.5em; }

    Hope this helps, and thanks a million for your article!

  4. Trying the source_editor.htm HEAD section again. (it stripped my html code from my last comment)

    Here are the CSS files I included:

    /js/codemirror/lib/codemirror.css
    /js/codemirror/mode/xml/xml.css
    /js/codemirror/mode/javascript/javascript.css
    /js/codemirror/mode/css/css.css

    and the JS files:

    /js/codemirror/lib/codemirror.js
    /js/codemirror/mode/htmlmixed/htmlmixed.js
    /js/codemirror/mode/xml/xml.js
    /js/codemirror/mode/javascript/javascript.js
    /js/codemirror/mode/css/css.js
    /js/codemirror/mode/htmlmixed/htmlmixed.js

Leave a comment

Your email address will not be published. Required fields are marked *