perfection kills

Exploring prototype by example

Updated Scripteka

April 29th, 2008 by kangax

Max and I have just updated Scripteka to version 1.1

In case you haven’t been following things around here, Scripteka is the prototype extensions library - a convenient place to find, rate and submit prototype.js based goodness.

The library still looks and feels the same, since our main goal was to improve overall usability and functionality.

Some of the new features include:

  • User Dashboard, where one can see all their scripts, and edit them.
  • Image upload for scripts. Finally, you can replace that default “empty page” image with your own.
  • Improved RSS feed with more useful information, and better formatting.
  • Improved communication and response to various actions. This includes:
    • Automated, token-based “claim script” feature. No more claiming script and not knowing what to do next.
    • More robust and informative feedback on script approval/rejection.
  • Small usability improvements.
  • Many bug fixes, polishing.
Categories: scripteka 3 Comments »

Namespacing made easy

January 30th, 2008 by kangax

Enumerable#inject is one scary method. It took me a while to understand the beauty of this functional programming paradigm. Just in case you were ever wondering about its real life usage - here’s one of them.

We all know that using namespaces is generally a wise thing to do. You don’t have to create a multi level object structure, but nesting your code under a pseudo-namespace is what makes maintenance, upgrades and migrations somewhat easier and error-prone.

Few popular javascript libraries implement some sort of a utility function that automatically creates nested objects. What it means is that instead of writing it manually, you could let the helper handle it for you:

 
// creating nested structure manually is painful
var com = {
  thinkweb2: {
    projects: {
      _prototype: 'a deeply nested property...'
    }
  }
}
 
com.thinkweb2.projects._prototype // => 'a deeply nested property...'

Well, it appears that inject can handle such task in only 3 lines of code:

 
'com.thinkweb2.projects.prototype'.split('.').inject(window, function(parent, child) {
  var o = parent[child] = { }; return o;
})
 
Object.inspect(com.thinkweb2.projects.prototype) // => "[object Object]"

Not bad - a completely generic namespacing snippet.

What’s happening here is not a black magic. Inject accepts initial object as a first argument (in this case - window object) and iterator function as the second argument. It then calls iterator function on each item from the collection (in our case it’s simply a string split into an array). Iterator function receives accumulated result as a first argument and current value as a second. Iterator performs an action (creates a nested object) and returns accumulated result (the newly created parent object) to be used in following iterations.

Alternatively, we could wrap this all nicely and define as a String.prototype method:

 
String.prototype.namespace = function(separator){
  this.split(separator || '.').inject(window, function(parent, child) {
    var o = parent[child] = { }; return o;
  })
}
 
foo.bar.baz.quux = 'Nothing special...'; // => ERROR: foo is not defined
 
// Default separator is '.'
'foo.bar.baz.quux'.namespace();
 
foo.bar.baz.quux = 'Nothing special...'; // => "Nothing special..."
 
// Or using a custom one
'MY_AWESOME_APPLICATION::util::DOM::dimensions'.namespace('::');
 
'dimensions' in MY_AWESOME_APPLICATION.util.DOM; // => true

Note how we use “separator” argument (or defaulting to ‘.’) making the function somewhat more flexible.

P.S.
Heavy namespacing could lead to unnecessary complexity.
Lack of it - to buggy behavior.
In the end, the only thing that matters is what works best for you.

Enjoy!

Categories: inject 12 Comments »

Prototype 1.6.0.2 Cheat Sheet

January 22nd, 2008 by kangax

Prototype 1.6+ cheat sheet

A long awaited Prototype cheat sheet - a full reference to a bleeding edge 1.6.0.2 is finally here. I had no experience creating something like this before, so any bugs or suggestions are very much appreciated. Couple of notes about notations:

  • Modules are sorted in a somewhat logical order - those commonly used are mostly in the left/center area, while deprecated/utility methods are all the way to the right
  • Method can be recognized by parentheses following it (anything that doesn’t have ones is a property)
  • Deprecated items are marked red and have NO parentheses/arguments specified
  • Prototype extends quite few native objects’ prototypes with a set of convenient methods. In such cases there’s an explicit note about it next to a module name - i.g. stripScripts() method from “String (String.prototype)” can be called as 'foo'.stripScripts()
  • When a module is also a class, there’s a “(constructor)” note next to it - i.g. “Hash (constructor)” means that it should be called as new Hash()
  • There are few bonus items (such as those from Prototype.Browser) which are not yet included in documentation

Download (9026 downloads) and Enjoy!

Update:
I have managed to choose the most retarded format for the cheat sheet - almost squared - which was impossible to print or navigate. Sincere apologies. There is an updated version at the same address which also fixes few other annoyances:

  • Ajax.Responders is now a separate section
  • Added missing Event.fire
  • Added Prototype.BrowserFeatures.XPath
  • Added simple “Dimensions/Offsets” diagram
  • Minor rearrangements

Update 2:
Uploaded a Higher Contrast version (2273 downloads)
Seems to look much better when printed.

Categories: cheat sheet 45 Comments »

Proto.IPS - In place select widget

December 22nd, 2007 by kangax

Proto.IPS

In place editing is a great way to enhance user interface when dynamically changing data on a page. Scriptaculous’ In Place Editor is a nice extension with extensive set of features and options. I recently needed such functionality in one of the projects, but IPE wasn’t exactly the best tool for the job. The idea was to let users select one of the predefined options as well as add their own. GMail chat widget and the way it allows to change availability status is a great example of such user interface addition. Another concern was to make control fit in a limited space - google simply gets rid of “Save”/”Cancel” buttons and saves value of the input field when clicking outside of control.

I tried duplicating this behavior into a simple prototype based script which can be simply plugged into any project.
This work is experimental (there are couple of known issues) and I would appreciate any feedback.

Head over to a demo page and let me know what you think.

Categories: Uncategorized 7 Comments »

Proto.Menu gets facelift

December 3rd, 2007 by kangax

Proto.Menu

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

Categories: extension, Proto.Menu 54 Comments »

« Previous Entries