Adding CodeMirror Editor

I needed an embedded editor with syntax highlighting. Here’s what I did to add CodeMirror (www.codemirror.net) to my project.

WARNING - this is not industrial strength code!! It is an experiment and should be treated as such. Use with caution!

It works by transforming an Anvil TextArea into a CodeMirror widget. You identify the control to transform by setting its role, and the JS gets applied to that element. You don’t have to use an Anvil component, you could just add an html <textarea> in your custom html form (because once it’s transformed it’s not really an Anvil component any more). I chose this way to give me some control over the positioning in the designer.

If anyone has a better way to do this - please share :slight_smile:

Create a custom html form and add :

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css" integrity="sha256-o/v/5fOniPHMAww4EAIfRBFV0SeoqksPrY0Yq5x+wSM=" crossorigin="anonymous" />
<script src="_/theme/CodeMirror.js"></script>
<script src="_/theme/codemirror-lua-min.js"></script>

Create a theme asset called “CodeMirror.js” and copy the contents of this URL into it (I just put that URL into the browser and cut/paste the resulting page) :
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.js

Create a theme asset for your chosen language syntax highlighter in the same way (I’m using Lua for this example so I created “codemirror-lua-min.js”) :
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/mode/lua/lua.min.js

For some reason I couldn’t link directly to the CDN versions, and I didn’t spend any time working out why. Here’s a page with all the CDN hosted files :

Add the following to your HTML asset :

<script>
  // Create a global array of editors if it doesn't already exist.
  var myMirrors=myMirrors || {};
  
  // The calling party must provide a previously created name.
  function get_text(name) {
	return myMirrors[name].getValue();    
  }
  
  // This turns the textarea into a codemirror widget.
  // "name" must be the role name assigned in Anvil to the TextArea.
  function init_editor(name) {
    var taid = document.getElementsByClassName('anvil-role-'+name)[0];
    var params = {lineNumbers:true};
    var myCodeMirror = CodeMirror.fromTextArea(taid,params);
    myMirrors[name] = myCodeMirror;
    
  }
</script>

In the designer, drag & drop a TextArea component onto the custom form (Form1).
Add the following to the code :

from anvil import *
import string
import random

class Form1 (Form1Template):
  def __init__(self, **properties):
    self.init_components(**properties)
    self.editor_name = self.generate_random_string()
    
  def get_text(self):
    return self.call_js("get_text",self.editor_name)
  
  def form_show (self, **event_args):
    self.text_area_1.role = self.editor_name
    self.call_js("init_editor",self.editor_name)
  
  def generate_random_string(self, size=6, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))

Create a new (normal blank) form in your project (Form2).
Drag & drop your custom form onto it (it will be called something like “custom_1” by default).

When you run the project, the text area should convert into a codemirror editor (with line numbers in the left hand margin).

You can retrieve the typed text by placing a button on Form2 and this code :

  def button_1_click (self, **event_args):
    # This method is called when the button is clicked
    print(self.custom_1.get_text())

This is just scratching the surface. I’m going to try and turn this into a proper reusable component over the next whenever.

1 Like

Ok, for the lazy amongst you :slight_smile:

https://anvil.works/ide#clone:TUFBCACMMLO72TSX=3WRBCMBQ2IPQCMSOZBRK4XLP

Slightly tidied up.

3 Likes

Lazy? I thought this forum was for programmers. :wink: