Tuesday, June 25, 2013

Z-Index is a Pain in Any Language

‹prev | My Chain | next›

I think that the Dart version of the ICE Code Editor has more or less reached the point that it could replace the one used in 3D Game Programming for Kids. This is, of course, the exact point that a project starts thinking about awesome feature creep, which we affectionately call 0.1.0.

Of the features and bugs on that list, the one that has bothered me the most is the lack of search and replace. This never even worked in the old JavaScript version, but it was only enough to annoy, not enough to push pass the myriad of other problems and address. Since the underlying ACE code editor supports search and replace (it even works fine on the project landing page), I must be doing something very dumb.

The dumb thing turns out to be that I never included the ext-searchbox.js code in either project. With it installed alongside the other ACE code, the ICE Code Editor now also boasts search and replace:



Or it would boast this support if the ICE Code Editor button controls were not getting in the way of the ACE search and replace box. This is more of a problem than it first appears. I cannot simply fiddle with the CSS z-index of the buttons and the search box. The buttons are in a <div> that is separate from the ACE container (again, the ACE code editor being part of the ICE Code Editor is ugly, but ICE was chosen before I was even aware of the existence of ACE, let alone opted to use it).

The ACE container has a z-index of 20. The search dialog has a z-index of 99 within that container. The problem is that the buttons have a z-index of 1000 in the same context as the ACE container. Any changes that I make to the z-index of the buttons only positions them relative to the ACE container, not anything within it like the search dialog. So if I give the buttons a z-index of 21, they still cover the search dialog with its z-index of 99 (withing the ACE container, z-index of 20).

So I am left with this problem: how do I make the search dialog cover the buttons?

I see no other option but to add the button toolbar directly to the ACE code editor <div> tag:
  _attachCodeToolbar() {
    var toolbar = new Element.html('<div class=ice-toolbar>');
    toolbar.style
      // styles
      ..zIndex = '89'; // below ACE's searchbox

    toolbar.children
      ..add(_updateButton)
      ..add(_hideCodeButton)
      ..add(_mainMenuButton);

    editor_el.children.add(toolbar);
  }
The problem with this approach is mostly sunk cost. I have spent a lot of time getting the show and hide code buttons working—especially with focus and delayed updates. I also have problems with the preview layer. If a “Show Code” toolbar is added to the preview layer, then I have to work very hard to add this toolbar back to the preview layer every time that it gets redrawn (which can be quite often). Last, but not least, I have several event handlers that ignore events inside of the ACE <div>, but now many of the menu events have been moved down inside there and I have my work cut out for me.

In the end, I opt for a hybrid approach to my problem. There really is no way to avoid adding the ICE toolbar buttons to the ACE <div>. So I simply deal with the event fallout, mostly by fixing tests that break. But I keep a toolbar above everything else—the “Show Code” toolbar, which only displays when the preview is displaying. That way, I can keep my sunk cost investment (at least for the time being) because it works and rely on the existing code to do the right thing with regards to which buttons should be visible at any given time.

It is not an ideal solution, but then again, I am not sure anything better is possible given my constraints. Bleh. Maybe something to follow up on another day.



Day #793

No comments:

Post a Comment