简体   繁体   中英

How to add code cells to HTML page with Javascript and Ace.JS?

Is it possible to create several text editor cells within a single page? My desired outcome is to have a button that when clicked allows the user to add new cells of code, where the user can write and later run. Similar to Jupyter notebook. The editor itself is imported from the ace.js library.

For that, I think I need some function add_editor(parent_div) that adds a new text editor to a div that is given as a parameter. ( Which I have failed to implement )

My initial thoughts are perhaps to create a shared class for all of the editors and append it to the father div with jQuery, but when I tried using a class instead of an id for the design,the editor won't load. I'm not so good with handling with the DOM (especially without React), so even if the solution seems obvious to you, it might not to me.

This is last working version of the code that I have so far

<html lang="en">
   <head>
      <title>ACE in Action</title>
      <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
      <!-- Define the editor's CSS !-->
      <style type="text/css" media="screen">
         #editor {
         width: 100%;
         height: 100%;
         }
      </style>
   </head>
   <body>
      <div class="row">
         <!-- a row of two columns: the first will contain the text editors, the second is irrelevant !-->
         <div class="col-9" style="height:200px;">
            <div class="container" style="">
               <div id="editor">
                  <!-- the div containing the code, has the id "editor" !-->
                  def print_something():
                  print(a)
               </div>
            </div>
         </div>
         <div class="col-3">
            empty column
         </div>
      </div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.5/ace.js" type="text/javascript" charset="utf-8"></script>
      <script>
         function configure_editor(){
             var editor = ace.edit("editor");
             editor.setTheme("ace/theme/monokai");
             editor.session.setMode("ace/mode/python");
             editor.getSession().setUseWrapMode(true);
             editor.setShowPrintMargin(false);
         }
         configure_editor()
         
      </script>
   </body>
</html>

Help will be much appreciated!

Edit: I need to solve this in Javascript or Jquery, without React.

I think I have found somewhat of a solution on my own with jQuery, even though it seems messy. Each time a new editor will be added with increasing ids, ie: "editor0", "editor1", "editor2", and so on.

Here is the full code

<html lang="en">
   <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
      <title>ACE in Action</title>
      <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
      <!-- Define the editor's CSS !-->
   </head>
   <body>
      <div class="row">
         <!-- a row of two columns: the first will contain the text editors, the second is irrelevant !-->
         <div class="col-9" style="height:200px;">
            <div id="editors_container">
            </div>
         </div>
         <div class="col-3">
            <button id="add_editor">Add a new editor</button>
         </div>
      </div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.5/ace.js" type="text/javascript" charset="utf-8"></script>
      <script>
          existing_editors = [];
          $(document).ready(function(){
            $("#add_editor").click(function(){
                console.log("reached here!")
                let editor_id = "editor"+existing_editors.length;
                $newDiv = $("<div id="+editor_id+" style=width:100%;height:100%>"+"</div>");
                $("#editors_container").append($newDiv);
                let editor = ace.edit(editor_id);
                editor.setTheme("ace/theme/monokai");
                editor.session.setMode("ace/mode/python");
                editor.getSession().setUseWrapMode(true);
                editor.setShowPrintMargin(false);
                existing_editors.push(editor);
            });
          });

      </script>
   </body>
</html>

A cleaner method is to assign an editor to each instance using your own structure. With jquery:

<div id="instance0"></div><div id="instance1"></div>

<script>

var instances[];

var $rootElement = $('#instance0');
newInstance($rootElement);
var $rootElement = $('#instance1');
newInstance($rootElememt);

function newInstance($rootElement){
    var instance = {};
    instance.id = $rootElement.attr('id');
    instance.$root = $rootElement;
    instance.editor = ace.edit($rootElement[0]);
    instance.editor.instance = instance;
    instances.push(instance);
}
</script>

This gives you a 1 to 1 instance to editor relationship with backpointers. It will save you much angst in the future. You can just flip in sessions and keep the editors static.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM