[Developer says] Handling multiple sessions with Ace editor

Hello! I’m Christos, and for the past year I have been the front-end developer here at codebender.

Our editor is based on Ace, a Javascript code editor. We have sketches, each of which contains multiple files. Because there are many files in a single sketch, we face the problem of having to handle multiple states of the editor, one for each file. In this blogpost we will see how to do that. It’s not that difficult, but I thought that it deserved an example. You can always reach the code at github. So, let’s begin.

First, we need an HTML page that will hold our example, as shown below:

<html lang="en">
<head>
<meta charset="utf-8">
<title>Ace with multiple sessions</title>

<link rel="stylesheet" href="assets/main.css">
</head>
<body>
<!-- editor container -->
<div id="editor-container">
  <div id="sidebar">
    <input id="create-file-input" type="text" name="input" placeholder="New file">
    <a id="create-file-button" href="javascript:void(0);">&plus;</a>
    <ul id="file-list"></ul>
  </div>
  <div id="editor"></div>
</div>

<!-- libraries -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-github.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-javascript.js"></script>

<!-- page scripts -->
<script src="assets/editorUI.js"></script>
<script src="assets/fileManager.js"></script>
<script src="assets/editor.js"></script>
</body>
</html>

At the top of the body, the div element with id=”editor-container”, contains:

  • A div element with id=”editor” which will hold our editor.
  • A div element with id=”sidebar” which will hold the editor’s sidebar, where we can create, remove, rename and select the files. Inside the sidebar we have an input field and a button to create new files as well the file list which gets populated by the created files and their rename/remove controls.
<!-- editor container -->
<div id="editor-container">
  <div id="sidebar">
    <input id="create-file-input" type="text" name="input" placeholder="New filename">
    <a id="create-file-button" href="javascript:void(0);">&plus;</a>
    <ul id="file-list"></ul>
  </div>
  <div id="editor"></div>
</div>

Next we will need jQuery and Ace in our sleeve.

<!-- libraries -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/theme-github.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.0/mode-javascript.js"></script>

Finally, three js files located into the assets folder: editorUI.js, fileManager.js and editor.js contain the Javascript which gives life to the editor and its sidebar.

<!-- page scripts -->
<script src="assets/editorUI.js"></script>
<script src="assets/fileManager.js"></script>
<script src="assets/editor.js"></script>

Their logic is separated into the editorUI functionality (editorUI.js), which makes all the necessary DOM changes and calls editor’s methods when the user interacts with the sidebar. The fileManager (fileManager.js), which holds each file’s session and the editor (editor.js), that holds the Ace editor instance and makes calls to the fileManager and to the editorUI.

In more detail:

  • The editorUI object listens for events produced by user interaction with the sidebar and makes the necessary updates to the page when a user creates, renames, removes or selects files.
  • The FileManager function is pretty basic. It stores in an object both the filename and the session of each available file. The session object contains the state of the editor for each file (content, cursor position, text selection, etc…). The file manager also contains methods that allow us to add, remove, rename or select a file.
  • The Editor function, initializes the Ace editor and has methods to add, remove rename or select a file.
/**
 * Editor: Holds the editor and its operations
 */
function Editor () {
  // Initialize editor
  this.mode = 'ace/mode/javascript';
  this.editor = ace.edit('editor', this.mode);
  this.editor.setTheme('ace/theme/github');

  // Initialize fileManager
  this.fileManager = new FileManager();
  // Start event listeners
  editorUI.startEventListeners();
}

These functions are the most important in Editor:

  • ace.createEditSession(), used to create a new session when adding a file and
  • editor.setSession(), used for setting a file’s session to the editor when selecting a file.
/**
 * Editor's file operations
 */
Editor.prototype.addFile = function (filename) {
  var self = this;
  var check = this.fileManager.addFile(filename, function () {
    return ace.createEditSession('', self.mode);
  });

  if (check) {
    editorUI.createFile(filename);
    this.selectFile(filename);
  }
};

Editor.prototype.removeFile = function (filename) {
  return this.fileManager.removeFile(filename);
};

Editor.prototype.renameFile = function (oldFilename, newFilename) {
  return this.fileManager.renameFile(oldFilename, newFilename);
};

Editor.prototype.selectFile = function (filename) {
  var session = this.fileManager.selectFile(filename);
  if (session) {
    this.editor.setSession(session);
    editorUI.selectFile(filename);
  }
};

The event listeners of the editorUI object invoke the editor’s methods when the user interacts with the sidebar elements. The editor talks back to the editorUI object, as well as to the file manager.

When adding a file, a new session is created and stored in the file manager as seen inside the editor’s addFile() method. The new file is selected and the stored session of the file is set as the session of the editor, as seen in the editor’s selectFile() method. When removing a file, the editor’s removeFile() method is used and the file is deleted in fileManager. Finally, when renaming a file, the editor’s renameFile() method is used and the stored session for the file is re-assigned to the new filename inside file manager. In all cases, the editorUI object methods update the sidebar elements accordingly.

If we open the index.html file with our browser, the final result looks like this:

Image missing

An editor with support for multiple files.

Thanks for stopping by and reading.