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 (svn). 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
staaky said:
#Love the new look, especially the desktop theme, super clean.
Nice updates.
One thing I noticed in the CSS is the use of multiple classname notation. I know that there was something about that in IE(6). I think it's only picking up the second classname when you use .first.second , might be worth looking into.
Don Albrecht said:
#This is excellent work. What I appreciate most, however, is your clear and detailed description of the decisions you put into building this release. Such lucid comments can be few and far between, but reading them helps us all to be better developers. Thank you for sharing.
Jota said:
#Excellent work. I still didn't test it but it is looking fab.
Congrats.
Venu Reddy said:
#Nice work its looks awesome.
kangax said:
#Guys,
thanks for a feedback!
@staaky,
Good catch. I'll definitely take a look at this issue.
Roland said:
#Wasn't
.observe('contextmenu', Event.stop)deprecated in 1.6?kangax said:
#Roland,
What exactly was deprecated?
As far as I know that's the best way to prevent contextmenu event on menu items (which was considered a bug in previous version).
Edje said:
#Very cool menu! I'm having trouble enabling disabled menuitems when certain elements on the page are right clicked. How do I do this? I've tried creating an onBeforeShow functions and messing with the menuItems, but no luck....
Can you help me?
albert said:
#Hi;
Very elegant solution.
¿¿ its posible to make "sub-menu" on pop-up menu ??
thks for u good work.-
Ludwig said:
#Hi,
first of all i have to say, great work you have done with this context menu.
But i wondering is it to use for example for items in a tree? and for this i guess it is nessesary to have the possibility to ad some attributes. For examples ids...
is there a way to to this?
i am not a really good programmer, because of this i ask
would be cool to have this menu for using in a treelist
best regards Ludwig
Carl said:
#It does not work in Opera 9.24.
Carl
Michael Sharman said:
#Great work! Just some small things on the documentation I found.
1. An extra closing brace is needed after the 'Save' menu item
2. When instansiating a new Proto.Menu the 'selector' comment says the following:
// context menu will be shown when element with class name of "contextmenu" is clicked
However the example is "contextArea" (not "contextmenu") and it should be the element id, not class name.
Fantastic work :)
edy said:
#I have a problem. I made a page with it and I have an error:
Error: $(document.body) has no properties
File: http://86.106.82.67/js/proto.menu.0.6.js
Line: 51
Why?!?!
Justin said:
#Quite a lovely little script you’ve got there!
It works wonderfully for me on a page I initially load right from the server, but if for instance I add new content to that page with an AJAX call, the context menus don’t work (don’t show up with a right-click) on the new content (yes, the new content includes tags with the appropriate className selectors that work just fine on the original content). I would presume this is because the Proto.menu script needs to somehow reinitialize the DOM to notice this new content. If I’m correct in this assumption, how would I go about doing this? There doesn’t seem to be a method I call that would reinitialize the DOM.
So... the way I’ve gotten it to work thus far is to create a new Proto.Menu object instance every time I get an AJAX response with new content back from my server ...which will eventually be quite frequently. I don’t know how well this will hold up under stress yet—if the old objects will be garbage collected and whatnot or if the users browser will eventually just freeze up. Any guesses? I suppose I’m just wanting some verification that this is how your cute little context menu library was intended to be used.
Thanks so much!
Justin
J. A. Rodriguez said:
#Hi,
I noticed a bug here:
this.options.fade = this.options.fade && !Object.isUndefined(Effect);
If I declare fade: true, just for kicks, without having the Effect library, this line should force fade = false for me, right? Well, it seems that Object.isUndefined(Effect) doesn't work as expected here because passing an undefined parameter to the function triggers an uncaught exception anyw