Perfection Kills

by kangax

Exploring Javascript by example

← back 895 words

Proto.Menu gets facelift

It’s been over 2 months since the last release of Proto.Menu – highly lightweight and easy-to-use prototype based extension aimed to make context menu creation as simple as possible. Version 0.5 happened to be quite useful (considering all the positive feedback). There were many requests for all kinds of features, but the goal was to keep things small and concise. After analyzing the source, I found few obvious drawbacks which were supposed to be taken care of long time ago. Trying not to bloat the code base, the script was rewritten with speed, size and accessibility in mind. The result is a new shiny version – still small and fast but is much more robust and accessible. Without further ado, here is what the new version is all about:

Prototype 1.6

Prototype 1.6 is finally out. Upgrading Proto.Menu to the latest revision was definitely a reasonable thing to do. Besides tons of great enhancements and speed improvements, RC1 fixed a “conextmenu” bug (which was taken into account in a previous version) – that fix itself made the script even more compact.

Iframe shim

We all know the notoriously famous IE6 bug – select elements don’t play nice, popping through any elements positioned on top (even when z-index is set to be higher). Unfortunately, IE6 is still the most used browser out there. I have no idea how this fix didn’t make its way into previous versions, but I believe that any self respectable extension should be taking care of this annoyance.


this.shim = new Element('iframe', {
   style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
   src: 'javascript:false;',
   frameborder: 0
});
...
if (Prototype.Browser.IE) {
   this.container.insert({
      after: this.shim.setStyle(Object.extend(Object.extend(elOffsets, elDimension), {
         zIndex: this.options.zIndex - 1
      }))
   })
}

zIndex option

When fixing the z-index bug, I realized that it might be convenient to explicitly specify z-index of a menu container. As web applications become more complicated, the number of various elements on a page increases. Modal windows, tooltips and other floating elements should interact nicely with each other. Proto.menu now has a zIndex option (which is internally used to set iframe z-index properly)


new Proto.Menu({
   ...
   zIndex: 500,
   ...
});

“beforeShow”, “beforeHide” and “beforeSelect” callbacks

Callbacks is something every extensions developer should consider adding to their scripts. They allow users to intercept script execution at certain moments – add, change or stop certain behaviour. Proto.Menu now supports 3 callbacks: beforeShow is called every time the right click occurs but before the menu was positioned and rendered. If you wish to intercept the left click on a document which “cancels” the menu, you can now use beforeHide callback. Note that it’s not executed on menu item selection, we have another callback for that – beforeSelect is executed after the menu item was clicked but before the menu container was hidden and item callback invoked. Note that all callbacks get an event object as a first argument.


document.observe('click', function(e){
   if (this.container.visible() && !e.isRightClick()) {
      this.options.beforeHide(e);
      this.container.hide();
   }
}.bind(this));

Better callbacks

Menu item callbacks sucked a lot in previous version. There was no way to get neither reference to a clicked element, nor anything else. This was probably one of the most requested features. To make everyone happy, callbacks now get event object as a first argument. You can now easily access any event’s properties/methods such as target (clicked element), mouse position, and others.


var menuItems = [{
   name: 'Select all',
   callback: function(e){
      if (e.target.match('input[type=checkbox]')) {
         e.target.up('form').select('input[type=checkbox]').each(function(el){
            el.checked = true;
         })
      }
   }
}, {
   ...
}];
...

“className” option

Another highly requested feature (and one of the big drawbacks of previous version) was a lack of descriptive images in menu items. Images definitely take user interface on a next level. Not only visually pleasing, they let us make decision faster and be more productive. Any menu item, besides name callback and other options, now supports a className which is then assigned to an anchor element. Image based menus have never been easier!

Semantic markup

The last but not least of the new features is a proper markup of a menu element. Instead of just set of links (I can’t believe I made it this way), the structure now actually represents its true essence – unordered list of anchor elements. Making the web a somewhat meaningful environment is definitely the right way to go – interface elements should represent their purpose and try to be more user-friendly. As usual, I am always looking forward to any bug reports/suggestions or just any feedback about this extension. Check out a

demo page

and have fun!

P.S.
Just to make things a little tidier, the extension now has an extensive set of unit tests (source). Unit tests are a wonderful way to maintain proper cross-browser functionality and behavior. Please let me know if you find any of them failing so that the bugs can be take care of quickly.

Version 0.6 is most likely the last one to be released under this name. Proto.Menu has been ported to a Prototype-UI framework and will continue to be developed as one of its components. UI.ContextMenu supports shadow, submenus, verious themes (including Mac OSX and Leopard ones) and is deeply integrated into the framework’s core. For a sneak preview of what to expect check out latest examples (update: no longer available)

Did you like this? Donations are welcome

comments powered by Disqus