Forum

Thread tagged as: Problem, Addons, Third-party

Issue adding CodeMirror Text Editor to Perch

I have been trying to integrate the CodeMirror code/text editor with Perch so as to take advantage of the editor's autocompletion functionality. Having placed the relevant files in /perch/addons/plugins/editors/codemirror/, I am using the the code below in the _config.inc file, which is located in the /codemirror/ folder:

<script type="text/javascript" src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="PERCH_LOGINPATH/addons/plugins/editors/codemirror/lib/codemirror.css" />
<link rel="stylesheet" href="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/show-hint.css" />
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/show-hint.js"></script>
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/xml-hint.js"></script>
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/mode/xml/xml.js"></script>

<script>
$(document).ready(function(){

        var set_up_codemirror = function(){
            $('textarea.codemirror:not([data-init])').attr('data-init', true).each(function(i, o){

// generic codemirror settings
            var dummy = {
                    attrs: {
                      color: ["red", "green", "blue", "purple", "white", "black", "yellow"],
                      size: ["large", "medium", "small"],
                      description: null
                    },
                    children: []
                  };

                  var tags = {
                    "!top": ["top"],
                    "!attrs": {
                      id: null,
                      class: ["A", "B", "C"]
                    },
                    title: {
                      children: ["title", "strong", "emph"]
                    },
                    placeName: {
                      attrs: {
                        name: null,
                        target: ["yes", "no"]
                      },
                      children: ["wings", "feet", "body", "head", "tail"]
                    },
                    plant: {
                      attrs: {name: null},
                      children: ["leaves", "stem", "flowers"]
                    },
                    wings: dummy, feet: dummy, body: dummy, head: dummy, tail: dummy,
                    leaves: dummy, stem: dummy, flowers: dummy
                  };

                  function completeAfter(cm, pred) {
                    var cur = cm.getCursor();
                    if (!pred || pred()) setTimeout(function() {
                      if (!cm.state.completionActive)
                        cm.showHint({completeSingle: false});
                    }, 100);
                    return CodeMirror.Pass;
                  }

                  function completeIfAfterLt(cm) {
                    return completeAfter(cm, function() {
                      var cur = cm.getCursor();
                      return cm.getRange(CodeMirror.Pos(cur.line, cur.ch - 1), cur) == "<";
                    });
                  }

                  function completeIfInTag(cm) {
                    return completeAfter(cm, function() {
                      var tok = cm.getTokenAt(cm.getCursor());
                      if (tok.type == "string" && (!/['"]/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1)) return false;
                      var inner = CodeMirror.innerMode(cm.getMode(), tok.state).state;
                      return inner.tagName;
                    });
                  }

// add codemirror to textarea
                  var textarea = $(o);
          var id = textarea.attr('id');
                  var editor = CodeMirror.fromTextArea(id, {
                    mode:  "xml",
                    lineNumbers: true,
                    extraKeys: {
                      "'<'": completeAfter,
                      "'/'": completeIfAfterLt,
                      "' '": completeIfInTag,
                      "'='": completeIfInTag,
                      "Ctrl-Space": "autocomplete"
                    },
                    hintOptions: {schemaInfo: tags}
                  });

            });

        $(window).on('Perch_Init_Editors', function(){
               set_up_codemirror();
        });

        set_up_codemirror();
    };
});
</script>

I've based the above code on the Perch docs and the ACE _config.inc file that's packaged with the ACE editor on the Perch website. I'm fairly certain that the issue rests with the 'id' variable: if I grab the id of a particular textarea using Firebug and specify it as the value of the id variable then everything works fine in that particular instance.

Any help would be greatly appreciated.

Ronan Doherty

Ronan Doherty 0 points

  • 6 years ago
Drew McLellan

Drew McLellan 2638 points
Perch Support

What problem are you seeing?

The editor is not initialising, i.e. there is a textarea with no editor attached to it. Here is a copy of the template, if that's of any help:

<p><perch:content type="textarea" id="bodyPara" label="Paragraph" help="" html="true" editor="codemirror" size="m" /></p>

...and here is the HTML output by Perch for a relevant textarea in the CMS:

<div class="field-wrap">
  <textarea id="perch_63_bodyText" name="perch_63_bodyPara" class="text large autowidth codemirror m html" rows="6" cols="40" style="width: 827px;"></textarea>
  <div class="clear"></div>
</div>
Drew McLellan

Drew McLellan 2638 points
Perch Support

Do you get any console errors?

Does set_up_codemirror() get called?

I actually managed to solve this issue. It turns out that the line below, which I had used in imitation of the ACE implementation, was redundant:

var id = textarea.attr('id');

Working solution:

<script type="text/javascript" src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="PERCH_LOGINPATH/addons/plugins/editors/codemirror/lib/codemirror.css" />
<link rel="stylesheet" href="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/show-hint.css" />
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/show-hint.js"></script>
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/addon/hint/xml-hint.js"></script>
<script src="PERCH_LOGINPATH/addons/plugins/editors/codemirror/mode/xml/xml.js"></script>

<script>
$(document).ready(function(){

        var set_up_codemirror = function(){

            $('textarea.codemirror:not([data-init])').attr('data-init', true).each(function(i, o){

            var dummy = {
                    attrs: {
                      color: ["red", "green", "blue", "purple", "white", "black", "yellow"],
                      size: ["large", "medium", "small"],
                      description: null
                    },
                    children: []
                  };

                  var tags = {
                    /*"!top": ["top"],
                    "!attrs": {
                      id: null,
                      class: ["A", "B", "C"]
                    },*/
                    title: {
                      children: ["title", "strong", "emph"]
                    },
                    placeName: {
                      attrs: {
                        name: null,
                        target: ["yes", "no"]
                      },
                      children: ["wings", "feet", "body", "head", "tail"]
                    },
                    plant: {
                      attrs: {name: null},
                      children: ["leaves", "stem", "flowers"]
                    },
                    wings: dummy, feet: dummy, body: dummy, head: dummy, tail: dummy,
                    leaves: dummy, stem: dummy, flowers: dummy
                  };

                  function completeAfter(cm, pred) {
                    var cur = cm.getCursor();
                    if (!pred || pred()) setTimeout(function() {
                      if (!cm.state.completionActive)
                        cm.showHint({completeSingle: false});
                    }, 100);
                    return CodeMirror.Pass;
                  }

                  function completeIfAfterLt(cm) {
                    return completeAfter(cm, function() {
                      var cur = cm.getCursor();
                      return cm.getRange(CodeMirror.Pos(cur.line, cur.ch - 1), cur) == "<";
                    });
                  }

                  function completeIfInTag(cm) {
                    return completeAfter(cm, function() {
                      var tok = cm.getTokenAt(cm.getCursor());
                      if (tok.type == "string" && (!/['"]/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1)) return false;
                      var inner = CodeMirror.innerMode(cm.getMode(), tok.state).state;
                      return inner.tagName;
                    });
                  }

                  var textarea = $(o);
                  var editor = CodeMirror.fromTextArea(o, {
                    mode:  "xml",
                    lineNumbers: true,
                    extraKeys: {
                      "'<'": completeAfter,
                      "'/'": completeIfAfterLt,
                      "' '": completeIfInTag,
                      "'='": completeIfInTag,
                      "Ctrl-Space": "autocomplete"
                    },
                    hintOptions: {schemaInfo: tags}
                  });

            });

        };

        set_up_codemirror();

        $(window).on('Perch_Init_Editors', function(){
               set_up_codemirror();
        });
    });
</script>
Drew McLellan

Drew McLellan 2638 points
Perch Support

Great stuff. Thanks.