Wednesday, October 17, 2012

Overboard with JavaScript Array Iterators

‹prev | My Chain | next›

Mr Doob's code editor has a nifty share feature. Clicking on the link will embed a gzip'd version of the current contents of the code editor in the hash portion of the URL: http://gamingjs.com/ice/#B/rVdbc9o4.... The programmer can then copy the URL and share their awesome code with friends. In the future, I need add a gallery to the Gaming JavaScript web site of awesome games that kids write but first, I need to fix a fairly alarming bug.

If you already have a project in the Gaming JavaScript fork of the code-editor, opening a shared link will overwrite that project. That would certainly have a chilling effect on sharing code. Today I fix that.

I think that the workflow should be something like: detect a shared link, create a new, untitled project, load the project, and optionally let the programmer rename the project.

The current implementation for handling location hashed documents looks something like:
if ( window.location.hash ) {
  var hash = window.location.hash.substr( 1 );
  // ...
  documents[ 0 ].code = decode( hash.substr( 2 ) );
}
This is why opening a shared link replaces the existing project. It overwrites the code in the first (which is the current) project. In fairness to the original Mr. Doob implementation of the code-editor, this behaved slightly different than it does in my fork. But I clearly need to change my fork.

So I change the documents[0] assignment to a new create function:
if ( window.location.hash ) {
  var hash = window.location.hash.substr( 1 );
  // ...
  create(decode(hash.substr(2)));
}
That create() function is mostly borrowed from similar functions in the code-editor:
var create = function(code, title) {
  if (!title) title = nextUntitled();
  if ( documents[ 0 ].filename != title) {
    documents.unshift({
      filetype: 'text/plain',
      autoupdate: documents[ 0 ].autoupdate
    });
  }

  documents[ 0 ].code = code;
  documents[ 0 ].filename = title;

  localStorage.codeeditor = JSON.stringify( documents );
};
Mostly borrowed except for the call to nextUntitled(). In that function, I got a bit iterator-crazy:
var nextUntitled = function() {
  var nums = documents.
    filter(function(doc) {
      return doc.filename.match(/Untitled/);
    }).
    map(function(doc) {
      return parseInt(doc.filename.replace(/Untitled\s*/, ''), 10);
    }).
    filter(function (num) {
      return !isNaN(num);
    }).
    sort();

  return 'Untitled ' + (nums.length == 0 ? 1 : nums[nums.length] + 1);
};
In there, I filter my code documents list so that I am only dealing with Untitled projects. Then I map the projects to remove "Untitled " from the names (i.e. I leave only "3" when mapping "Untitled 3"). I also convert string numbers to real numbers, recalling that it is always best to be explicit with the JavaScript radix. That will not work for all Untitled projects, so I filter out any not-a-numbers from the list. Finally, I sort the list. After all that, I might be left with a list like: [1, 2, 3, 4]. I take the last number on that list, add one, and I have the number of my next Untitled projected (e.g. 'Untitled 5').

I probably enjoy iterators a bit too much.

Anyhow, with that, when I load a shared link, I now have a new Untitled project in the projects list:


I take a little time to replace similar code with a call to the new create() function and call it a night.

Day #542

No comments:

Post a Comment