Friday, April 5, 2013

Breaking Monolithic JavaScript into Separate Classes

‹prev | My Chain | next›

I have reached the point that I have to break up the ICE Code Editor. I have two different use cases for the editor and strewing conditionals throughout a monolithic codebase is getting old.

Much of the code is quite coupled, so I start by breaking the recent embedded code out into an API. My first pass will expose only an ICE.attachEmbedded() function that will find <script> tags with the type attribute set to "text/ice-code" and create a new ICE.Editor instance associated with it. I am not wed to this API—this only seems a good starting place.

In a new ice-embedded.js file, I start with a closure that will export ICE.attacheEmbedded() (is that really a closure then?):
(function(){

if (!window.ICE) ICE = {};
ICE.attachEmbedded = attachEmbedded;

})();
Most of the code that goes into ICE>attachEmbedded() is from my efforts over the past few days. I iterate over the <script> tags to create new instances of the embedded ICE Editors:
function attachEmbedded() {
  iceCodeScriptTags().forEach(function (script) {
    new Embedded(script);
  });
}
Where the Embedded class mostly does the work of attaching a new ICE Editor instance and doing some prep work:
function Embedded(script) {
  this.script = script;
  this.sourcecode = this.processSource();
  this.el = this.createEmbeddedElement();
  this.editor = new ICE.Editor(this.el);
  this.editor.setContent(this.sourcecode);
}
As for the editor itself, this is also newly extracted into a (different) class file. I define the constructor and export it:
(function(){

function Editor(el, options) {
  this.el = el;

  if (typeof(options) != "object") options = {};
  this.edit_only = !!options.edit_only;

  this.preview_el = this.createPreviewElement();
  this.editor_el = this.createEditorElement();
  this.editor = this.initializeAce();
  this.applyStyles();
}

if (!window.ICE) ICE = {};
ICE.Editor = Editor;

})();
Again most of those methods are extracted from the monolithic codebase. The important thing is the setContent() method which is invoked by the Embeded instance. I have that set the content of the editor and update the visualizations layer:
Editor.prototype.setContent = function(data) {
  this.editor.setValue(data, -1);
  this.editor.getSession().setUndoManager(new UndoManager());
  this.updatePreview();
};

Editor.prototype.updatePreview = function() {
  console.log('[updatePreview]');
};
For now, the updatePreview() method is a tracer bullet. If all goes right, I should have my editor and hit that tracer bullet.

I do not get either. At least not at first. It takes a bit of fiddling, but eventually I do get it. Mostly, I had not converted what were previously global variables into instance properties. Once I have that sorted out, I have my editor and my tracer bullets are hitting the mark:



It is not much, but it is a start. Hopefully tomorrow I can finish work on the embedded editors and get started on the full page editor with controls.

Day #713

No comments:

Post a Comment