Friday, April 12, 2013

Ghost Scripts

‹prev | My Chain | next›

I believe that I have all of the functionality restored in the object-oriented version of the ICE Code Editor (the code editor used for 3D Game Programming for Kids). Most of the fixes were minor errors on my part, missing features that needed to be copied from the monolithic version, or tweaks to support classes being split. Everything seems to be working, but there is a nagging little bug—not something that seems to affect performance, but sufficient to annoy. And annoying bugs can sometimes be the tip of the proverbial iceberg.

The problem occurs when I switch projects. For instance, when I switch from a Physijs-based project to a pure Three.js-based project, I see console errors like:
Uncaught TypeError: Object [object Object] has no method 'simulate' 
The old physics project is no longer visible and the new pure Three.js project is visible:



So it really does seem like everything is OK. But why the error?

Interestingly, the simulate() method comes from Physi.js. So this error would seem to be coming from the original Physi.js project, not the new Three.js project. In other words, updating the preview layer of the ICE Code Editor no longer seems to get rid of the old content.

To test this theory, I create two very simple setInterval() projects. One says "hi" and the other "howdy":
<body></body>
<script>
  setInterval(function(){console.log("howdy");}, 5*1000);
</script>
Sure enough, when I switch from one to the other, I end up with ongoing console output from both:
howdy localhost/:2
hi localhost/:2
howdy localhost/:2
hi localhost/:2
At first glance, the updatePreview() method of the core ICE.Editor class seems to be doing the right thing. It grabs the iframe holding the preview layer and overwrites the content document:
Editor.prototype.updatePreview = function() {
  // ...
  var iframe = this.getPreviewIframe();
  var content = iframe.contentDocument || iframe.contentWindow.document;

  content.open();
  content.write(
    this.editor.getValue()
  );
  content.close();
  // ...
};
I also use the Inspector in Chrome to verify that the content of the iframe is replaced and that there is only the single iframe. It would seem that, even though that DOM and code is removed, the executing context remains. So I have to be a little more aggressive with the preview layer's iframe. I need to remove it entirely:
Editor.prototype.updatePreview = function() {
  // ...
  while (this.preview_el.children.length > 0) {
    this.preview_el.removeChild(this.preview_el.firstChild);
  }

  var iframe = this.getPreviewIframe();
  var content = iframe.contentDocument || iframe.contentWindow.document;

  content.open();
  content.write(
    this.editor.getValue()
  );
  content.close();
  // ...
};
Bugger.

This is how the code used to work before I started trying to get the iframe to play nicely with the application cache. This seemed like an innocuous change at the time. I likely have been sticking with the same project since then so I might not have noticed the problem that I introduced a while ago.

Shame I do not have any automated tests built up around this thing. Then again, I can only imagine what a pain such a test would be to write. Anyhow, with the last of the problems solved, it is time to start adding new features. Tomorrow.


Day #720

No comments:

Post a Comment