Tuesday, June 17, 2008

What's New in MooTools 1.2

posted by Jonah Dempcy

I'm happy to announce that MooTools (Wikipedia link) has released version 1.2 of their excellent JavaScript library. MooTools, which stands for 'My Object Oriented Tools', was developed in 2006 by Valerio Proietti and his colleagues. It evolved out of Moo.fx, a lightweight effects library which plugged into the Prototype framework. It was similar, although smaller (and in my opinion, better) than the scriptaculous library. Moo.fx has now been fully integrated into the MooTools library and is not being developed further at this time.

Even before MooTools' 1.0 release on January 29, 2007, it had garnered quite a bit of buzz. There were even cheat sheets created for the beta MooTools library.

Thus, it is with great excitement that I announce a new version of this marvelous framework, with a great deal of improvements and additions to the codebase. I've been using 1.2 beta for quite a while and I think the official release is mostly a bug fix of the beta, so if you've been following this blog, chances are you've already been exposed to some of the new features in 1.2. Regardless, here's a full list of features and enhancements you'll find in the new release:

  • Swiff, support for working with Flash SWF files, similar to the swfobject library
  • Element storage allows you to store data in custom properties on HTML elements without leaking memory in IE
  • Overhaul of Fx classes with many improvements, including creating a Tween class to create reusable animation tweens
  • Overhauled Ajax requests; renamed Ajax class to Request , with JSON and HTML subclasses (for easily handling their respective data formats as Ajax responses)
  • Element.Dimensions - makes it a breeze to get width, height, x/y coordinates of an element (either relative to document or to positioning context) and scroll height/width
  • Created a Browser class to store browser, platform and feature information (e.g. whether the browser supports XPath or not). Before, browser info was stored on the window object. Also, this release renamed the properties from browser names to rendering engine names, e.g. trident4 instead of ie6.
  • In addition to the changes to the API and codebase, the following changes occured as well:

  • MooTools now adheres to behavior driven development using specs
  • The Hash Object - with get, put, each, some and a whole lot of other methods for manipulating data in a hash
  • MooTools developed using Git instead of Subversion now - this will only affect you if you're used to grabbing code from svn (or if you're a contributor!)
  • MooTools uses Lighthouse instead of Trac for bug tracking now

In light of all these improvements to an already excellent library, I think it's apparent that MooTools is really growing up and coming into its own. It's a force to be reckoned with and certainly a heavyweight contender against Prototype, jQuery, YUI and others.

I hope you've enjoyed this brief overview of some of the new features in MooTools 1.2. Now get out there and start coding!

Related links:
Docs and Demos
Compatibility
Git Repositories
Bug Tracking
MooTools User Groups

Labels: ,

Thursday, June 12, 2008

Stylize the last element in jQuery

posted by Alex Grande
Here is how to stylize the border of the last element using jQuery.
$(document).ready(function() {
    $("table.innercart tr:last").css("border", "none");
});
You can compare to prototype by going here

Labels: ,

Stylize the last element in prototype

posted by Alex Grande
Here is an example of removing the last border in a list of elements.
Event.observe(window, "load", function() {
    $$(".homepageContainer .upcomingEvents").last().setStyle({
        border: 0
    });
});
You can compare to jQuery by going here

Labels: ,

Tuesday, May 20, 2008

Inspecting Javascript with Firebug

posted by Alex Grande
1. Go to http://www.alexgrande.com/breakable/ and add the link to your bookmarks.


2. Go to the page you are interested in inspecting and click on the bookmark in your browser called "Inspect JS". That will load breakable.js into the head of the page you are currently using.


3. In firebug go into the scripts tab and view breakable.js.
4. Set a break point on line 7 where it says funct();


5. Find out what the ID is of the element that has the event listener.


6. Click the console tab in firebug. Type in: breakOn("elementID", "eventTrigger"); Example: breakOn("prettyImageOver", "onmouseover"); Example 2: breakOn("ajaxImageChanger","onclick");


7. (1)Initialize the event by mousing over it or whatever you you chose as the event trigger. If the original js author chose a mouse over event then you should also use a mouse over event. Because if you choose an onclick for an onmouseover event then by the time you click it the event has already passed you by..
8. (2)Firebug will transfer over to the breakable.js in the scripts tab at the breakpoint funct(). Step into it by (3)clicking the arrow right in firebug script section.


9. and you will enter into the javascript code of whatever function is called by the event.


I love this! Big thanks to my friend Grady Morgan for writing this short script!

Labels: ,

Wednesday, May 14, 2008

JavaScript Challenge: Reverse a Linked List

posted by Jonah Dempcy

This article is a follow-up on my previous post on writing a linked list class in MooTools. In that post, I offered an implementation of a singly-linked list in JavaScript and gave a challenge: To reverse a linked list in place, starting with only a reference to the head. The challenge also forbade the use of storing the data externally -- that is to say, you can't just iterate over the linked list and stuff the items in a new array, then reverse the array.

As promised, here is my solution to the challenge. If you are planning on trying the challenge yourself, read no further.

I've included the code for defining the LinkedList and LinkedListItem classes as well. It's separate from my solution, so if you want to give it a try yourself, go ahead and copy the code below.

var LinkedList = new Class({

    // Input: Array collection
    // An array of items to turn into a singly linked list
    
    initialize: function(collection) {

        this.collection = new Array();
                   
        // Construct the linked list
        collection.each(function(item, i) {
            var item = new LinkedListItem(item);
            this.collection.push(item);
            
            if (i > 0) {
                this.collection[i - 1].setNext(item);
            }
        }.bind(this));
        
        this.setFirst(this.collection[0]);
    },
    
    // Input: LinkedListItem item
    // Sets the head to be the given item
        
    setFirst: function(item) {
        this.head = item;
    },
        
    // Returns: LinkedListItem head
    
    getFirst: function() {
        return this.head;
    },
    
    // Returns: Array result
    // An array with all items' values, in the order they are linked
    
    getAll: function() {
       var result = new Array();
       
       result.push(this.getFirst().getValue());
       
       var item = this.getFirst().getNext();
       while (item) {
           result.push(item.getValue());
           item = item.getNext();
       }
       
       return result;
    }
});

// This class defines an individual item in the linked list.
// The value it is instantiated with is stored in the value property,
// and is accessible via getter/setter methods.

var LinkedListItem = new Class({
    initialize: function(item) {
        this.value = item;
    },
    
    getNext: function() {
        return this.next;
    },
    
    setNext: function(item) {
        this.next = item;
    },
    
    getValue: function() {
        return this.value;
    }
});

For an in-depth discussion of this code including step-by-step commentary, check out the previous article, LinkedList Class in MooTools.

Reverse a Linked List: Solution

This is what I came up with:

window.addEvent('domready', function() {

    var list = new LinkedList(['a', 'b', 'c', 'd', 'e', 
                               'f', 'g', '1', '2', '3', 
                               '4', '5']);

    // Challenge: Reverse the linked list in place (list.collection) 
    //            without using another array

    // Input: LinkedList list

    function reverseLinkedList(list) {

        // Inputs: LinkedListItem item, LinkedListItem next
        //
        // Returns true if next item exists
        // If not, sets the head to be the existing item
        
        function checkForNextItem(item, next) {
            if (!$defined(next)) {
                list.setFirst(item);
                return false;
            } else {
                return true;
            }
        }
        
        // Our new tail is the old head
        var tail = list.getFirst(); // 0

        var itemOne = tail.getNext(); // 1

        // If there is only one element in the list, return it
        if (!$defined(itemOne)) {
            return list;
        }
        
        // Remove the old link from the tail
        tail.setNext(null);                      

       // Prepare third item variable for while() loop
        var itemThree = tail;
        
        // The while() loop will stop when the checkForNextItem() 
        // function fails to find a next item and calls 
        // list.setFirst() on the final existing item.
        
        while (list.getFirst() == tail) {
            
            itemTwo = itemOne.getNext(); // 2
            itemOne.setNext(itemThree); // link 1 to 0            
            if (!checkForNextItem(itemOne, itemTwo)) break;
                              
            itemThree = itemTwo.getNext(); // 3            
            itemTwo.setNext(itemOne); // link 2 to 1
            if (!checkForNextItem(itemTwo, itemThree)) break;
            
            itemOne = itemThree.getNext(); // 4
            itemThree.setNext(itemTwo); // link 3 to 2
            checkForNextItem(itemThree, itemOne);                       
            
        }
        
        return list.getAll();  
    }
    
    console.log('Forward: ' + list.getAll()); 
    console.log('Backward: ' + reverseLinkedList(list));
    
    // RESULT:
    //
    // Forward: a,b,c,d,e,f,g,1,2,3,4,5
    // Backward: 5,4,3,2,1,g,f,e,d,c,b,a    
});

The main part of the function that does the work of reversing the linked list is the while() loop. I use a helper method, checkForNextItem(), which is declared at the top.

You'll notice I declared the function inside the reverseLinkedList() function. The reason I did this is that checkForNextItem() is a private method that shouldn't be accessible to code outside of the scope of the reverseLinkedList() function. Just like declaring local variables when you don't need a global, you can declare private methods inside the scope of the function block. It's perfect for helper methods like this and it doesn't clutter the global namespace.

To explain what the checkForNextItem() actually does, let's examine the while() loop where it's used.

        while (list.getFirst() == tail) {
            itemTwo = itemOne.getNext();
            itemOne.setNext(itemThree);         
            if (!checkForNextItem(itemOne, itemTwo)) break;
                              
            itemThree = itemTwo.getNext();           
            itemTwo.setNext(itemOne);
            if (!checkForNextItem(itemTwo, itemThree)) break;
            
            itemOne = itemThree.getNext();
            itemThree.setNext(itemTwo);
            checkForNextItem(itemThree, itemOne);                              
        }

The while() loop continues until list.getFirst() no longer returns the tail (the old head). At that point, the loop knows to finish because the checkForNextItem() method, unable to find a next item, will set the head to be the final remaining item in the list. Thus, the old tail becomes the new head and the linked list is reversed.

The only other area of the code which warrants discussion is the check if there is only one item in the list, and calling setNext(null) on the new tail (the former head):

        // Our new tail is the old head
        var tail = list.getFirst(); // 0

        var itemOne = tail.getNext(); // 1

        // If there is only one element in the list, return it
        if (!$defined(itemOne)) {
            return list;
        }
        
        // Remove the old link from the tail
        tail.setNext(null);        

The check to make sure itemOne is defined is simply a fail-safe for linked lists with only one item. In that case, tail.getNext() will be undefined so we just return the list as it is, with only one item. Originally I wrote the check using the JavaScript typeof keyword (i.e. if (typeof itemOne == 'undefined')), but then I remembered to use MooTools' nifty $defined() method which is both more succinct and easier to read (in my opinion).

Besides the check for single-item lists, I also had to remove the old link from the tail (formerly the head). If you don't remove the link, the while() loop will never end, since the tail will link to the next-to-last item which links back to the tail, forever and ever. So that's why I call tail.setNext(null) there.

Refactoring the Code

After writing this, something just didn't feel right about the while() loop. It was messy and seemed to be doing the same thing 3 times. I remembered back to the first time I solved this challenge and recalled a more elegant solution. After changing the code, I ended up with this:

window.addEvent('domready', function() {
    var list = new LinkedList(['a', 'b', 'c', 'd', 'e', 
                               'f', 'g', '1', '2', '3', 
                               '4', '5']);


    // Input: LinkedList list
    // Returns: LinkedList list (reversed)

    function reverseLinkedList(list) {

        // Our new tail is the old head
        var current = list.getFirst(); // 0

        // If there is only one element in the list, return it
        if (!$defined(current.getNext())) {
            return list;
        }
                
        var previous = null;
        var next;       
        
        while (current != null) {
            next = current.getNext();
            current.setNext(previous);
            previous = current;
            current = next;        
        }
        list.setFirst(previous);
        
        return list;  
    }
    console.log('Forward: ' + list.getAll()); 
    console.log('Backward: ' + reverseLinkedList(list).getAll());
    
    // RESULT:
    //
    // Forward: a,b,c,d,e,f,g,1,2,3,4,5
    // Backward: 5,4,3,2,1,g,f,e,d,c,b,a    
});

This code is more optimized and nicer to read. It has the same functionality but the while() loop has been significantly simplified and the checkForNextItem() method has been eliminated altogether. It's a good thing when you can reduce complexity like that.

One other minor edit I made during refactoring was to change the function from returning list.getAll() to just returning the list itself. After thinking about it, I prefer for the input and outputs to both be of type LinkedList and then you can just call getAll() on the result. It's a minor nuance but worth pointing out.

Leave comments if you'd like a deeper explanation of a specific area of the code or if anything is unclear, and of course your own implementations are always welcome.

Labels: , ,

Tuesday, May 13, 2008

LinkedList Class in MooTools

posted by Jonah Dempcy

A commonly used data structure in Java and other programming languages is the linked list (Wikipedia). It is similar to an array in that it is a way to store a collection of objects in sequence, however unlike an array you cannot access items in the collection by index. Instead, you access them through links from other items in the collection, or from the initial head or tail link (which can typically accessed with getFirst() and getLast() methods, respectively).

Data Structure - Linked List

Each item in the collection has a getNext() method which returns the next item in the collection. If it's a doubly-linked list then each item (save for the head and tail) will have both getNext() and getPrevious() methods.

In JavaScript, no such construct exists, so we'll create one. This is mostly for academic purposes but there's nothing to stop you from using it in real code if you're so inclined. For the sake of this practice, we'll just make a singly-linked list as it is a bit simpler.

This also provides an introduction to defining classes in MooTools. We aren't using much MooTools-specific functionality here so it could easily be ported to another library, or even written without the use of a library. But, since I use MooTools for most of my projects, I decided to use it here. I think you'll find defining classes in MooTools to be quite easy.

The LinkedListItem Class

Here is the code to define the LinkedListItem class. The LinkedListItem takes a value of any type (string, object, etc) and returns an object of type LinkedListItem, which has the original value stored as the value property on the object. It also defines accessor methods for getting/setting the next item in the list. There is also an accessor method for getting the original value.

// This class defines an individual item in the linked list.
// The value it is instantiated with is stored in the value property,
// and is accessible via getter/setter methods.

var LinkedListItem = new Class({
   initialize: function(item) {
       this.value = item;
   },
  
   getNext: function() {
       return this.next;
   },
  
   setNext: function(item) {
       this.next = item;
   },
  
   getValue: function() {
       return this.value;
   }
});

Read on to see how the LinkedListItem class is used by the LinkedList.

Defining the LinkedList Class

The LinkedList class will take an array of objects of any type and create a linked list from those objects. The linking occurs in the order of the array. So, if you call it with ['a', 'b', 'c'] you'll get back a linked list with a as the head, and c as the tail. The list will be linked like so: a -> b -> c.

The LinkedList class has three methods: setFirst(), getFirst() and getAll(). The former two are accessor methods for changing the first element, i.e. the head. The latter is a method which returns an array of all the items in the linked list, in the order they are linked.

There are quite a few other methods you could implement for the LinkedList but for now, these will suffice. If you're particularly brave and inclined to add to the class, go ahead and check out the Java LinkedList docs to see what other methods are available.

Here's the LinkedList class I came up with:


var LinkedList = new Class({
  
   // Input: Array collection
   // An array of items to turn into a singly linked list
  
   initialize: function(collection) {

       this.collection = new Array();
                 
       // Construct the linked list
       collection.each(function(item, i) {
           var item = new LinkedListItem(item);
           this.collection.push(item);
          
           if (i > 0) {
               this.collection[i - 1].setNext(item);
           }
       }.bind(this));
      
       this.setFirst(this.collection[0]);
   },
  
   // Input: LinkedListItem item
   // Sets the head to be the given item
      
   setFirst: function(item) {
       this.head = item;
   },
      
   // Returns: LinkedListItem head
  
   getFirst: function() {
       return this.head;
   },
  
   // Returns: Array result
   // An array with all items' values, in the order they are linked
  
   getAll: function() {
      var result = new Array();
     
      result.push(this.getFirst().getValue());
     
      var item = this.getFirst().getNext();
      while (item) {
          result.push(item.getValue());
          item = item.getNext();
      }
     
      return result;
   }
});

There are only two areas of the code that need explaining: constructing the list in the initialize() method, and constructing an array from the list in the getAll() method. I'll touch on each to make sure it is clear what exactly is going on.

The initialize() method is called on each instance of the class, with the arguments given to the constructor of the class. Calling new LinkedList(['foo', 'bar']) will call the initialize() method with the argument ['foo', 'bar'] as well. This is an automatic function call handled by MooTools and should not be done manually, unlike Prototype where the developer must manually call the initialize() method after instantiating the class.

The first thing our LinkedList initialize() method does is create the collection property. This is so it can store the data internally, and this property is not meant to be publicly accessible to other code. The collection array will be used to store the LinkedListItem objects created from the input array.

I use MooTools each() method to iterate over the items in the input array (collection). For each item, I create a new LinkedListItem and add it to the collection property where it will be stored. I then set the previous item's link (if it exists) to the current item, using the setNext() method.

Finally, once the each() loop has finished iterating over all the items in the collection, I set the head link to be the first item in the array, using the setFirst() method.

The other interesting area is the getAll() method, which does basically the opposite of the initialize() method. Instead of constructing a LinkedList from an array, the getAll() method returns an array in the order of the LinkedList. So you could instantiate a LinkedList in a certain order, change the order around by various setNext() calls, and then call getAll() and get back an array in the new order. This might not seem very useful at the moment, but bear with me and I'll demonstrate its utility through a challenge or two.

The getAll() method uses a while() loop instead of an each() loop, because we don't know the length of the list. Even if the length of the collection array is 10, for instance, we have no guarantee the list will be 10 items. The coder may have called setNext(null) on the head, in which case the list would only have a length of 1. Therefore, we must use a while() loop that continues as long as their are next items, in other words, as long as getNext() on the current item is not null.

Inside the while() loop, we simply add the current item to the result array and then redefine the item variable to point to the next item. After the loop finishes, we return the result, which is an array in the order that the list is linked.

You can test that this works by instantiating a LinkedList and calling getAll() on it.

window.addEvent('domready', function() {

   var list = new LinkedList(['a', 'b', 'c', 'd',
                              'e', 'f', 'g', '1',
                              '2', '3', '4', '5']);

   console.log(list.getAll());
  
   // RESULT:
   // a,b,c,d,e,f,g,1,2,3,4,5
});

LinkedList Challenge

Next up, a LinkedList challenge! Can you write code that reverses a linked list in place, without creating a new array?

My next post will provide an answer, but in the meantime, give it a try. To make it clear, the challenge is to reverse a singly-linked list, using either the LinkedList class defined here or your own implementation, in place. That is, without creating another array, hash or other data structure to store the data in the list temporarily before writing it again.

This is the expected outcome:

   var list = new LinkedList(['a', 'b', 'c', 'd',
                              'e', 'f', 'g', '1',
                              '2', '3', '4', '5']);

   console.log('Forward: ' + list.getAll());
   console.log('Backward: ' + reverseLinkedList(list));
  
   // RESULT:
   //
   // Forward: a,b,c,d,e,f,g,1,2,3,4,5
   // Backward: 5,4,3,2,1,g,f,e,d,c,b,a   

I should also mention that you can't access the collection array inside the linked list directly. Otherwise, you could just do something like this:

function reverseLinkedList(list) {
   return list.collection.reverse();
}

That would be a cheap, and is not an acceptable solution. This challenge is to reverse the list in place, so your only choice for starting is to call getFirst() on the list:

function reverseLinkedList(list) {
   var head = list.getFirst();
}

This challenge was given to me in Java by my mentor at Amazon, Chris. It took me a good 45 minutes to solve the first time (though Chris made me solve it on a whiteboard, which is always more difficult for me than typing it up). Good luck and stay tuned for the next post which will offer a solution to this challenge.

Labels: ,

Monday, May 12, 2008

JavaScript Challenge: Dispense Change

posted by Jonah Dempcy

This challenge is to write a function that takes an amount of change and returns a String Array with the coins to dispense.

Examples:

  • .25 returns ['quarter']
  • .26 returns ['quarter', 'penny']
  • .30 returns ['quarter', 'nickel']
  • 1.01 returns ['dollar', 'penny']
  • 1.16 returns ['dollar', 'dime', 'nickel', 'penny']

One of the requirements is that this returns the least amount of units of currency as possible. In other words, you can't return 100 pennies or even 4 quarters when 1 dollar would suffice. This is modeled after how real-life vending machines work.

Land of the Vending Machines Land of the Vending Machines By gullevek

If you want to attempt to solve this challenge yourself, read no further! The rest of the article will go on to describe my solution to this problem and some of the issues I encountered along the way.

Using MooTools' round() Method

I originally wrote my solution to this challenge without the use of JavaScript libraries. However, I ran into a common problem when dealing with dollar values, which is that I needed to round them to the 2nd decimal place. Without rounding to the 2nd place, you end up with subtle flaws in the data.

For instance, I was using an if() statement to check if the change remaining to dispense is greater than or equal to 0.1 (one cent). Before I added the code to round to the 2nd decimal place, the if() statement wouldn't evaluate to true when there should be a penny left to dispense. The change remaining should have been .1, but it wasn't entering the if(changeToDispense >= 0.1) statement. How could this be? Well, I was subtracting the change, but upon closer inspection, some of the values were not what I expected. When I subtract .25 from .48, I ended up with 0.22999999999999998 for instance.

Of course, I should have ended up with 0.23, not .022999 (repeating). But, without rounding the number, it ended up slightly less than the correct amount, introducing subtle bugs into the code. Since the full amount wasn't being subtracted, the last penny would never be dispensed because there wasn't a whole penny left (it was something like 0.09999999999999998). Thus, I rounded to the second decimal place and it solved the problem.

Using core JavaScript methods, it's possible to work around this problem. It involves multiplying by 100, rounding and then dividing by 100. But, since most of the projects I work on use JavaScript libraries and nearly all of them have round() functions in some form or another, I decided to get a little help from a library. Specifically, I use the MooTools round() method for solving this problem.

The round() method takes how many places after the decimal to round to, so by calling round(2), a number like 0.0999 (repeating) is converted to 0.1.

Vending Machine - Japan Vending Machine - Japan By rytc

Note that as the method is added to the prototype of the Number object (i.e. base class), it is called as an instance method of the number you want to round, not as a method of the Math object as with core JS methods. Compare:

  • Core JS: Math.round(1.8);
  • MooTools: 1.8.round();

Designing a Solution

My idea for the solution is to store a hash of the coin values keyed by their name, and then iterate over them checking if each value is higher than the amount of remaining change to dispense. For this to work, I need to iterate over them in order from highest to lowest. Otherwise, if I start in random order, it will break one of the requirements: This must return the least units of currency as possible. If I start at the penny, then it would keep dispensing pennies until there was no change left, and never get on to the other units of currency.

Therefore, the loop needs to iterate over the currency values in order of highest to lowest: dollar, quarter, dime, nickel, penny. Here is the hash object that I created to represent the currency values, and then we'll discuss how to iterate over them in order:

 var money =
     'dollar': 1.00,
     'quarter': 0.25,
     'dime': 0.10,
     'nickel': 0.05,
     'penny': 0.01                                 
 };

You might think it's as easy as using a for/in loop, but unfortunately, browser compatibility issues prevent it from being this simple. Using a for/in loop will iterate over the items but there is no guarantee of the order. Internet Explorer and Firefox use the correct order (the order of declaration) as far as I know, but Safari in particular does not follow this. So, it's not as simple as:

function dispenseChange(changeToDispense) {
 var result = new Array();
 for (var unit in money) {
     if (money[unit] > changeToDispense) result.push(unit);
 }
 return result;
}

It would be nice if it were this simple, and indeed in most browsers it is. But due to obscure quirks with the order of iteration over objects of properties, we need to store the order in its own array.

Asahi Beer Vending Machine: Komatsu Asahi Beer Vending Machine: Komatsu By jpellgen

A Working Solution

I've changed the money object to now contain two properties, a values hash and an order array.

 var money = {
     values: {
         'dollar': 1.00,
         'quarter': 0.25,
         'dime': 0.10,
         'nickel': 0.05,
         'penny': 0.01                                 
     },
     order: ['dollar', 'quarter', 'dime', 'nickel', 'penny']
 };

Now I can iterate over the order array and use that to key the values hash. It's one extra step in the process but it doesn't add too much bloat to the code, and it actually works (at least, in the browsers I've tested):

function dispenseChange(changeToDispense) {         
 var result = new Array();
 while (changeToDispense.round(2) >= 0.01) {
     for (var i = 0; i < money.order.length; i++) {
         var value = money.values[money.order[i]]; // Number, e.g. 1.00
         if (changeToDispense.round(2) >= value) {
             result.push(money.order[i]); // String, e.g. "dollar"
             changeToDispense -= value;
             break;                      
         }
     }
 }
 return result;
}   

You can test the function with logging statements:

window.addEvent('domready', function() {
 var tests = [.01, .05, .11, .27, .74, 1.08, 1.99, 2.07];
 tests.each(function(testValue) {
     console.log(testValue.toString() +
                 ': ' +
                 dispenseChange(testValue)
     );
 });
});

Improving the Implementation

One area for improvement is the nested for() loop inside the while() loop. Right now it isn't ideal, since it will waste iterations checking for currency amounts higher than the current currency. To explain what I mean, let's look at the loop again:

 while (changeToDispense.round(2) >= 0.01) {
     for (var i = 0; i < money.order.length; i++) {
         // ...
         if (changeToDispense.round(2) >=
             money.values[money.order[i]) {
             // dispense unit of currency
             break;                      
         }
     }
 }

I commented out some of the implementation details so we can focus on the structure. The reason that this is sub-optimal is that after each unit of currency is dispensed, the for() loop breaks and the while() loop starts it over again. Say there is less than a dollar remaining to dispense-- for each unit of currency dispensed, the for() loop will still check for a dollar.

To optimize this code, we'd have to only iterate over the order array once. This means the for() loop would be outside the while() loop, and for each unit of currency, the while() loop would continue to dispense change of that unit until the change remaining is less than the unit's value. It would be optimized to n (see Big O notation for details) at that point.

Optimized Code

Here is the new and improved code with the optimized loops:

var money = {
 values: {
     'dollar': 1.00,
     'quarter': 0.25,
     'dime': 0.10,
     'nickel': 0.05,
     'penny': 0.01                                 
 },
 order: ['dollar', 'quarter', 'dime', 'nickel', 'penny']
};
function dispenseChange(changeToDispense) {
  
 var result = new Array();
 money.order.each(function(unit, i) {
     var value = money.values[unit]; // Number, e.g. 1.00
     while (changeToDispense.round(2) >= value) {
         result.push(unit); // String, e.g. "dollar"
         changeToDispense -= value;
     }
 }); 
 return result;
}
  
window.addEvent('domready', function() {
 var tests = [.01, .05, .11, .27, .74, 1.08, 1.99, 2.07];
 tests.each(function(testValue) {
     console.log(testValue.toString() +
                 ': ' +
                 dispenseChange(testValue)
     );
 });
});

An observant reader will notice that I changed the for() loop to use MooTools' each() method. The reason I did this is that we no longer need to break out of the for() loop, and I prefer the each() notation. (Thanks for recommending it, Lowell!)

As always, feel free to post your own solutions to this challenge in the comments.

The latest in Japanese vending machines
The latest in Japanese vending machines By El Fotopakismo

Labels: , ,

Saturday, May 10, 2008

jQuery drop down menu delay (setTimeout)

posted by Alex Grande
To create a navbar with a subnav (drop down menu for instance) with a delay before closing using jQuery (jQ) follow this code. An example can be found here. Javascript (js):
function navbar() {
// create variables
var subNavTimer;
var open;
// to make sure that when user mouses over sub menu ul it stays open
$("ul.subNav").mouseover(function() {
 $(this).show();
 // lets remember what's open
 open = $(this).parent();
});
 
// when user mouses over main item in navbar
$("li.navMainLink").mouseover(function() {
 // close other nav item submenus
 if (open != null) open.children("ul").hide();
 // stop the timer
 clearTimeout(subNavTimer);
 // show this nav item's sub menu
 if ($(this) != open) $(this).children("ul:hidden").show();
 
});

// when user's mouse leaves the navbar item
$("li.navMainLink").mouseout(function() {
 // lets keep tabs of what is open
  open = $(this);
 // start the timer for 2 seconds until it closes.
  subNavTimer = setTimeout('open.children("ul:visible").hide();', 2000);
});
}

$(document).ready(function() {
 navbar();
});
HTML:
<ul id="navMain">
<li class="navMainLink">
  <a class="navLink" href="#">Performances</a>
  <ul class="subNav">
   <li>
    <a href="#">Season Subscriptions</a>
   </li>
   <li>
    <a href="#">About the Shows</a>
   </li>
  </ul>
 </li>
</ul>
CSS: Your decision! Make it a vertical drop down or make it a horizontal fly out. Just make sure to have the ul.subNav be display: none; by default in your CSS.

Labels: , ,

Thursday, May 8, 2008

Using MooTools' Hash.Cookie API

posted by Jonah Dempcy

MooTools makes working with cookies quite easy. Based on functions from Paul Peter Koch's QuirksMode, the MooTools API for handling cookies is intuitive and easy to remember.

For storing simple bits of information on the browser, the Cookie methods read(), write() and dispose() are adequate. As their names imply, these read, write and delete cookies from the browser, respectively.

But, if you want to do something more complex, such as save a JSON string each time a method is called on the cookie, then Hash.Cookie is for you.

What's the difference between the Hash.Cookie methods and the standard methods you say? For one, Hash.Cookie is its own module, so make sure the version of MooTools you're using has it included. Besides that, Hash.Cookie gives you all the functionality of the Hash class, including getters/setters, each(), some(), filter(), has(), keyOf() and more. For the full documentation on all Hash methods available, view the Hash docs here.

Here's an example that uses the Hash.Cookie class to store how many times a user has visited the page. Note that this uses Firebug so if you don't have it enabled, you'll need to override console.log().

window.addEvent('domready', function() {
    var cookie = new Hash.Cookie('test-cookie');
    
    var numberOfVisits = $defined(cookie.get('numberOfVisits')) ? 
                         cookie.get('numberOfVisits') :
                         0;
                         
    cookie.set('numberOfVisits', numberOfVisits + 1);
    
    console.log('You have visited the page ' + 
                 cookie.get('numberOfVisits') + 
                 ' times.');        
});

On line 1, we start by declaring everything to occur when the DOM is ready. For MooTools developers, this should be a familiar practice. Although we aren't manipulating the DOM in this example, I've left it in, as Firebug threw an error when I tried to console.log() before the DOM was ready.

On line 2, we instantiate a new cookie named 'test-cookie' without any options. Interestingly, this also has the effect of loading the cookie if it already exists. This means that the first time the user visits the page, it will write a cookie, but on all subsequent visits it will read a cookie. The end result is the same: we have a reference to the cookie as a hash object, and can use the methods that the Hash class provides.

Next, on lines 4-6, we use a ternary operator to check if 'numberOfVisits' has already been written to the cookie. If so, we read it from the cookie. If not, it is initialized to 0.

On line 8, we increment 'numberOfVisits' using the set() method. Finally, we log the number of visits using Firebug's console.log().

Getters, Setters and Auto-Saving Cookies

Getters and setters should be familiar to anyone versed in Java but I imagine some JavaScript developers may be unfamiliar with them. Essentially, get() and set() methods are provided for you to use instead of directly accessing the data. For instance, cookie.hash.numberOfVisits and cookie.get('numberOfVisits') both return the same data, but the former directly accesses the data while the latter uses a wrapper method.

There are numerous reasons to use getters/setters instead of directly accessing the data, but one practical example is the use of Hash.Cookie's autoSave functionality. There is an autoSave flag in the options which, if enabled, will save the data after each operation on the hash. It defaults to 'true' which is why I didn't have to write() the cookie in the above example.

Since I didn't define a duration in the options object when instantiating the cookie (nor did I even include an options object, for that matter), it will only live for the duration of the browser. In other words, it's a session cookie: When the user exits the browser and restarts, the cookie will be destroyed. For the cookie to live beyond the lifespan of the browser, you can specify the duration of the cookie to live (in days).

The other options which I omitted were domain, path and secure. None of those were important for my example but for some applications, setting domain- and path-specific cookies and ensuring they are only accessed over HTTPS may be necessary

This example is somewhat simple but I hope it has provided an introduction to using MooTools' excellent Hash.Cookie API. Good luck and enjoy a tall glass of soymilk with your Hash Cookies!

Labels: , ,

Monday, May 5, 2008

Downloading the Full MooTools Library

posted by Jonah Dempcy

One of my minor frustrations on the MooTools download page has always been having to manually select each component to add. While it is nice that you can keep the filesize down by omitting components that you don't need, I wish they had a way to select all components at once.

Well, it turns out they do. I just found out that Mootools actually allows you to select all components by calling the Download.all() method. You can do this by opening the Firebug console while you're on the MooTools download page and entering Download.all() and clicking Run. Alternately, if you don't have Firebug, you can enter javascript:Download.all() into the addressbar and press enter. This will select all components on the page.

Labels: ,

Saturday, April 26, 2008

Retaining Middle-Click Functionality With JavaScript

posted by Jonah Dempcy
Image used under a Creative Commons license. Source

Browsers such as Firefox and Internet Explorer 7 allow users to middle-click on links to open them in a new tab. Oftentimes, JavaScript will be used to add an onclick event to a link that supersedes the link itself. But, when a Firefox or IE7 user middle-clicks the link they may be confronted with any number of sub-par user experiences, such as the new tab containing the same page they were on, or a blank page.

In order to prevent this from happening, a non-JavaScript fallback must be present. Some people only think about the small (estimated less than 5%) amount of users who have JavaScript disabled, and choose not to support those users. That's a conscious decision and I certainly understand it, and condone it as long as there are clearly defined messages to the JS-disabled user that they need to enable JavaScript to use the page.

However, what some people fail to recognize is that even the 95% of users with JavaScript enabled will have sub-par user experiences if there are not non-JS fallbacks cases like this, where middle-clicking a link does nothing but waste the user's time. In order to offer the best user experience and fully utilize the capabilities of the browser, a conscientious JavaScript developer must take a number of measures that might not be apparent at first glance.

When Should Middle-Click Functionality Be Retained?

There are many uses for JavaScript onclick events. Not all of them will need to support the middle click. To determine if it does, ask yourself if it appears as a link to the user. If it looks like a link (be it text, image or button that appears to lead to another page) then it should support middle-click behavior. If it is another use for an onclick event, for instance, a button that clearly performs an action on the current page, then no alternative is necessary.

Take the case of a fancy search results widget that heavily uses JavaScript and Ajax to present search results. Users with JavaScript disabled are presented with instructions on how to enable it, and informed that they won't be able to use the site with out it. So far so good, but unless the search results have a non-JavaScript fallback (unlikely) then middle-clicking them will not have the expected result of some users, which is to take the user to a product detail page.

A real life example: I was interested in tickets to a jazz show and visited the tickets page for that festival. It has a link saying "Watch a video of this artist." I middle-clicked the link, as I usually do, but the next tab contained the exact same information I had just seen-- no video in sight. I inspected the HTML to see that it was a link, but the href was set to "#", in other words, an empty name on the same page.

When I left-clicked the anchor tag, it executed a JavaScript function and opened a popup showing the video. But, middle-clicking proved pointless, as it was a "dummy" anchor tag that should have been a span with cursor: pointer in the CSS.

In fact, I quite commonly see JavaScript onclick events on anchor tags, where the anchor tag serves no other purpose than to make the mouse cursor a pointer. Take the following code, for example:

<a href="#" onclick="showMoreResults();"gt;Show more results</a

If you left-click the link, it will take you to the top of the page (implicit in the "#" name) and execute the showMoreResults() function, which does an Ajax call to fetch more search results, let's say. So far so good. But if you middle-click the link, it will take you to the same page without executing the function. Furthermore, if it's a complex JavaScript application, the state of the application may be lost. In the case of search results, the newly-opened tab may have reset back to the original state of the application, frustrating the user. Of course they can just close the tab and use their existing tab, so all is not lost, but it is still a waste of time from the user's perspective.

If it is truly a JavaScript feature which does not appear as a link, the wise developer would remove the user's ability to middle-click it. By changing it to a span tag, middle-clicking would do nothing.

On the other hand, if it actually looks like a link (and in this case, I think it does), then a middle-click fallback would be nice. Say the user wants to open the next page of search results in the new tab, but stay on the existing page in this tab. Middle-clicking should work, right?

How to Retain Middle-Click Functionality

The way to do this is to set the href attribute of your anchor tags to a page presenting the user with the same content they would get by left-clicking. So, if your app uses Ajax to load in new results by left-clicking, then middle-clicking should take them to the same results on a new page. This is accomplished by setting the href attribute with the correct URL to the content. If you're on search-results.php?page=1 then you would need to set the href to be search-results.php?page=2. The solution varies from app to app but the general idea is to make sure that the href of the link leads to the content advertised in the link.

Next, you need to make sure the onclick event returns false. If you're using inline event registration, it looks like this:

<a href="search-results.php?page=2" onclick="showMoreResults(); return false;">Show more results</a>

This is the same as a non-JavaScript fallback for links. It's a good idea to do this anyway, regardless of middle-click support, as approximately 1-in-20 users will have JS disabled anyway (although this number may vary depending on your particular target market).

Something else to keep in mind is that if you are outputting the href from the server and then showing new results with JavaScript, you'll need to update the href tag as well. Otherwise, you could go to page 1, click "Show more results" and view page 2's results, and then middle-click "Show more results" and be presented with page 2's results again. Why? Because the href was set on page 1 to show page 2's results, and the JavaScript loaded in new results using Ajax. The solution to this is to make sure you update the href to display the correct content each time the application state changes, be it with Ajax or otherwise.

It's fairly straightforward-- if you're on page 10, then when the showMoreResults() function is called you load in new results for page 11 with Ajax, and set the href of the "Show more results" link to point to page 12.

This is just one example using search results, but the same principle applies to any JavaScript actions that the user perceives as links. When middle-clicking the link, or clicking it with JavaScript disabled, the user should be presented with the right content. Otherwise, they will feel like the site is broken, or like they did something wrong. Instead, make sure you've always placed non-JavaScript and middle-click fallbacks in your pages.

Whenever adding an onclick, ask yourself if it looks like a link or a button that would take the user to a new page. Unless the onclick is operating directly on the contents of the current page and it's obvious to the user, consider using the methods outlined above.

Labels: ,

Wednesday, April 23, 2008

PHP Starter Template

posted by Jonah Dempcy

Since Alex posted his HTML Starter Template article last week I was inspired to condense some of my starter code for building sites in PHP.

I use Aptana to code, so whenever I make a new project, I start by copying in files from 2 template projects I've made, xhtml-template and php-template. Each project has its own file structure and stub files. Since Alex already posted a thorough XHTML starter, I'll focus on the PHP template today.

The files and folders I include are as follows:

  • components
    • banner.php
    • doctype.php
    • footer.php
    • global.php
    • head.php
    • sidebar.php
  • css
    • styles.css
  • images
  • js
    • main.js
  • offline-files
    • docs
    • mocks
  • index.php
All of the PHP files in the components folder can be used by the pages on the site if need be, or deleted if not.

This is how I include the files on the homepage, index.php:


<?
   include($_SERVER['DOCUMENT_ROOT'] . '/components/global.php');

 $metaTags['keywords'] = '';
 $metaTags['description'] = '';
 $metaTags['author'] = '';
 $metaTags['copyright'] = '';
 $metaTags['charset'] = 'UTF-8';
 
 $pageTitle = '';
 $pageId = '';

   include($_SERVER['DOCUMENT_ROOT'] . '/components/head.php');
?>

<body>
   <? include($_SERVER['DOCUMENT_ROOT'] . '/components/banner.php'); ?>


   <? include($_SERVER['DOCUMENT_ROOT'] . '/components/footer.php'); ?> 
</body>

Inside the Components Directory

Here are the default contents of those files:

global.php

<?php
 $metaTags = new ArrayObject();
 $metaTags['keywords'] = '';
 $metaTags['description'] = '';
 $metaTags['author'] = '';
 $metaTags['copyright'] = '';
 $metaTags['charset'] = 'UTF-8';
 
 $pageTitle = '';
?>

This file contains global variables used by the whole site. You could store constants here as well. The $metaTags array stores the default meta tags for the site, which can be overridden on a per-page basis.

This page also contains the default page title for the whole site, stored in the $pageTitle variable. Again, this should be overridden on a page by page basis (for best SEO benefits) but it's just a fallback in case you forget to define the title of that page.

banner.php

<div id="banner">
 
</div>

The banner file doesn't actually contain any PHP code, just an empty div tag. It's a stub, ready to be added to if the site needs a banner (and really, most sites do).

You could go a step farther by adding in a default image, or h1 and h2 tags with CSS image replacement, but for me, this is sufficient.

doctype.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

You could combine the doctype file with the head file. It just comes down to preference for how granular you like the files to be, really.

footer.php

<div id="footer">
 
</div>

This is another stub. You could put default information such as copyright (using the &copy; HTML entity perhaps), or a homepage link. But I just leave it empty and customize it for whichever site I'm working on.

head.php


<?php include('doctype.php'); ?>

<head>
 
 <!-- CSS -->
 <link rel="stylesheet" href="css/styles.css" />

 <!-- Meta tags --> 
 <meta name="keywords" content="<?php echo $metaTags['keywords'] ?>" />
 <meta name="description" content="<?php echo $metaTags['description'] ?>" />
 <meta name="author" content="<?php echo $metaTags['author'] ?>" />
 <meta name="copyright" content="<?php echo $metaTags['copyright'] ?>" />
 <meta name="robots" content="FOLLOW,INDEX" />
 <meta http-equiv="Content-Type" content="text/html; charset=<?php echo $metaTags['charset'] ?>" />
 <meta name="MSSmartTagsPreventParsing" content="true" />
       <meta http-equiv="imagetoolbar" content="no" />  
 <!-- Title -->
 <title><?php echo $pageTitle; ?></title>
 
 <!-- Shortcut icon -->
 <link rel="shortcut icon" href="/favicon.ico"  />

</head>

The head has some fun features. Let's go through one by one. First we include the doctype, as shown above. Then we start the head and include the default CSS file, styles.css.

Next we include a number of meta tags, including a few you may not have heard about before. For instance, we include <meta http-equiv="imagetoolbar" content="no" /> which causes IE to stop showing that annoying disk icon in the bottom right of images when you hover over them. We also include copyright and author tags, and another one to inform MS apps not to try to parse it with SmartTags. (I got this one from Blogger templates).

After that, we just define the title (that's a must) and link the default favicon file.

An observant reader will notice that we didn't define the JavaScript in the head. The reason for this is that it usually hurts page performance to define it in the head. In this page template, I didn't include the link to the template, but I recommend either adding it to the footer.php file after the closing div or creating a new file like so:

javascript-includes.php

<script src="/js/main.js" type="text/javascript"></script>



Default JavaScript to Include

As for JavaScript, I don't have a lot of helper methods or anything that I like to include since that is all taken care of by the library, ideally. But I do include this one piece of code which enables CSS background-image caching in IE:
// IE6 does not cache CSS background images by default.
// This code enables CSS background caching for the lifespan of the browsing session in IE6.

try {
    document.execCommand('BackgroundImageCache', false,true);
} catch(e) {};

Other than that, I don't really include any boilerplate code. But suggestions are welcome! What default JavaScript templates do you use? Feel free to post your own in the comments.

Default CSS to Include

I am a big fan of Eric Meyer's reset styles. My default CSS pretty much looks like that:
/* Reset styles (adapted from Eric Meyer's Reset Reloaded) */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
 margin: 0;
 padding: 0;
 border: 0;
 outline: 0;
 font-weight: inherit;
 font-style: inherit;
 font-size: 100%;
 font-family: inherit;
 vertical-align: baseline;
}
/* remember to define focus styles! */
:focus {
 outline: 0;
}
body {
 line-height: 1;
 color: black;
 background: white;
}
ol, ul, li {
 list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
 border-collapse: separate;
 border-spacing: 0;
}
caption, th, td {
 text-align: left;
 font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
 content: "";
}
blockquote, q {
 quotes: "" "";
}

/* Site styles */

/* Legend:


*/

/* Sitewide */

body {
 font-size: 11px;
 font-family: Helvetica, Arial, sans-serif;
 color: #000000;
}

h1 {
 font-weight: bold;
 font-size: 27px;
}

h2 {
 font-weight: bold;
 font-size: 16px;
 color: #000000;
}

h3 {
 color: #000000;
 font-size: 15px;
 font-weight: bold;
}

h4 {
 font-size: 12px;
 font-weight: bold;

}

h5 {
 color: #000000;
 font-size: 11px;
}


a:link {
 color: #000000;
 text-decoration: none;
}
a:visited {
 color: #000000;
 text-decoration: none;
}

a:hover {
 color: #000000;
 text-decoration: underline;
}

a:active {
 color: #000000;
 text-decoration: underline;
}

/* wrapper */

div#wrapper {
    
}

/* banner */

div#banner {
    
}

/* footer */

div#footer {
    
}

I could probably stand to update the CSS a bit. Right now the stubs are, well, just stubs-- I intend to add stronger default styles that are consistent with most site defaults nowadays. Maybe that will be the topic of a future article. Regardless, this is a nice blank slate to start out with.

What is your default template for starting websites? Comments are encouraged.

Labels: , ,

Thursday, April 10, 2008

Redefining console.log() For Browsers Without Firebug

posted by Jonah Dempcy
Firebug

I use Firebug's console.log() method extensively when developing code. But, when viewing the site in Internet Explorer, Safari, Opera or other browsers that don't have Firebug, console.log() throws an error. Rather than wrap each log statement in a try/catch, I just add this bit of code during development that checks for Firebug and redefines the console.log() method if Firebug isn't installed:

 // When logging messages with console.log()
 // if user doesn't have Firebug, write them to the DOM instead
 if (typeof console == "undefined") {
 
  // Create an unordered list to display log messages
  var logsOutput = document.createElement('ul');
  document.getElementsByTagName('body')[0].appendChild(logsOutput);
  
  // Define console.log() function
  console = {
   log: function(msg) {
    logsOutput.innerHTML += '<li>' + msg + '</li>';
   }
  };
 }

Logging Statements in Production Code

If you don't want to have to remove your console.log() statements in production code, you can set a "development mode" flag that ignores log messages.
var DEVELOPMENT_MODE = true;

// When logging messages with console.log()
// if user doesn't have Firebug, write them to the DOM instead
if (typeof console == "undefined" && DEVELOPMENT_MODE == true) {
 
  // Create an unordered list to display log messages
  var logsOutput = document.createElement('ul');
  document.getElementsByTagName('body')[0].appendChild(logsOutput);
  
  // Define console.log() function
  console = {
    log: function(msg) {
      logsOutput.innerHTML += '<li>' + msg + '</li>';
    }
  };
} else if (DEVELOPMENT_MODE == false) {
  console = {
    log: function() {} // Do nothing
  };
}
I made the flag uppercase since it follows naming conventions for constants. Now you can set the DEVELOPMENT_MODE flag when deploying to production environments and leave your logging messages intact, if you desire.

Take note that this adds unnecessary page-weight from the logging messages, so to fully optimize the code, logging should be removed. But, leaving some amount of logging in the production code is probably acceptable, as long as it doesn't add more than a few kilobytes to the page weight. As long as you're using GZip, minifying your JavaScript and serving it with far future expires headers, a few extra k aren't going to hurt anything.

Redefining All Firebug Methods

If you use other Firebug methods, such as assert(), trace() or error(), then you may want to use the following code, provided by the developers of Firebug as part of the Firebug Lite project.

This code redefines all Firebug methods as empty functions when Firebug isn't installed on the browser:
if (!window.console || !console.firebug) {
  var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
  "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

  window.console = {};
  for (var i = 0; i < names.length; ++i)
    window.console[names[i]] = function() {}
}

Labels: , ,

Wednesday, April 2, 2008

JavaScript Challenge: Cardinal Numbers

posted by Jonah Dempcy


This challenge is to write functions to add and subtract numbers using the names of numbers as strings. More precisely, the challenge is to write add() and subtract() functions that take two strings as input, and return one string. For example:
add("one", "ten"); // should return "eleven"
subtract("twenty", "fifteen"); // should return "five"
For the purposes of this exercise, we will limit the maximum numbers handled to 99. So, you don't have to handle, say, add("three-thousand-five-hundred-and-fifty-two", "ten-million-and-seven"). Though, you certainly get bonus points if you handle this case as well.

Here is my solution below, which is by no means optimal. The following is my first attempt at solving this issue, coded in roughly 30 minutes, so go easy if you find any SNAFUs.

Note: I prefer 4-space indentation but I set it to 2-space for this article so the code example will fit on the page without horizontal scrolling.
var cardinalNumbers = {
    "one": 1,
    "two": 2,
    "three": 3,
    "four": 4,
    "five": 5,
    "six": 6,
    "seven": 7,
    "eight": 8,
    "nine": 9,
    "ten": 10,
    "eleven": 11,
    "twelve": 12,
    "thirteen": 13,
    "fourteen": 14,
    "fifteen": 15,
    "sixteen": 16,
    "seventeen": 17,
    "eighteen": 18,
    "nineteen": 19
}

var multiplesOfTen = {
    "twenty": 20,
    "thirty": 30,
    "forty": 40,
    "fifty": 50,
    "sixty": 60,
    "seventy": 70,
    "eighty": 80,
    "ninety": 90
}
                        
function convertWordToNumber(word) {
  var number = new Number(); // this is where we will store the result              
  
  if (word.indexOf("-") == -1) { // If it is less than 20
    number = cardinalNumbers[word];
  } else {
    var multipleOfTen = word.split("-")[0];   // e.g. "seventy"
    var cardinalNumber = word.split("-")[1];   // e.g. "six"
    number = multiplesOfTen[multipleOfTen] + cardinalNumbers[cardinalNumber]; 
  } 
  
  return number;
}

function convertNumberToWord(number) {
  var word = new String(); // this is where we will store the result
    
  if (number < 20) {
    for (var cardinalNumber in cardinalNumbers) {
      if (number == cardinalNumbers[cardinalNumber]) {
        word = cardinalNumber;
        break;
      }
    }
  } else if (number < 100) {
    if (number % 10 == 0) { // If the number is a multiple of ten
      for (var multipleOfTen in multiplesOfTen) {
        if (number == multiplesOfTen[multipleOfTen]) {
          word = cardinalNumber;
          break;
        }
      }
    } else { // not a multiple of ten
      for (var multipleOfTen in multiplesOfTen) {
        for (var i = 9; i > 0; i--) {
          if (number == multiplesOfTen[multipleOfTen] + i) {
            word = multipleOfTen + "-" + convertNumberToWord(i);
            break;
          }
        }
      }
    }
  } else {
    alert("We don't handle numbers greater than 99 yet.");
  }
    
  return word;
}

// These functions takes words as inputs, e.g. "one" and "two"

function add(x, y) {
  return convertNumberToWord(convertWordToNumber(x) + convertWordToNumber(y));
}

function subtract(x, y) {
  return convertNumberToWord(convertWordToNumber(x) - convertWordToNumber(y));
}


// Test convertWordToNumber()
alert(convertWordToNumber("three"));               // should alert 3
alert(convertWordToNumber("seventy-three"));       // should alert 73   


// Test convertNumberToWord()
alert(convertNumberToWord(8));                     // should alert "eight"
alert(convertNumberToWord(46));                    // should alert "forty-six"


// Test add() 
alert(add("one", "two"));                          // should alert "three"

// Test subtract() 
alert(subtract("fifteen", "eleven"));              // should alert "four"
Feel free to post your solutions in the comments. Particularly good solutions will get an entire article devoted to them.

Labels: ,

Thursday, March 27, 2008

JavaScript Method Overloading

posted by Jonah Dempcy


A feature of languages such as Java, C# and C++ is the ability to overload methods with multiple parameters. Overloaded methods execute different code depending on the type and amount of parameters supplied-- in other words, the type signature of the method. Thus, overloading methods allows for a more flexible API which can handle different possible signatures.

Here's an example of how it works in Java. Let's say that I have a record collection and want to be able to add records by name, ID number, or a Record object:
public void addRecord(String name) {
 // implementation details
}

public void addRecord (Number id) {
 // implementation details
}

public void addRecord(Record record) {
 // implementation details
}
This is convenient because I can call addRecord() elsewhere in the code and use whatever data is available at that time.

Unfortunately, JavaScript does not currently allow you to do this, at least not in this manner. One reason for this is that JavaScript does not have type signatures for its methods. The signatures of JavaScript methods are simply the names of the parameters, without any type information.

Compare:

Java
public void addRecord(String name) {}
JavaScript
function addRecord(name) {}
As you can see, JavaScript method declarations do not have the types of return values or parameters. This makes sense given that JavaScript is not a typesafe language, or a strongly typed language at all.

Regardless, JavaScript 2.0 will support method overloading inherently (so-called 'multifunctions'), but for now, we're left to devise our own solutions to this.

JS Method Overloading: A First Attempt



If your method only has a single argument, it's fairly easy to overload a method.

For instance, here's an overloaded method that hides an element, given either its id (a string) or the HTML object itself.
function hideElement(element) { // takes id of element (string) or HTML obj
  if (typeof element == 'string') {
      element = document.getElementById(element);
  }
  element.style.display = 'none';
}
In this example, a check of the argument's type (using the typeof keyword) determines if it is a string. If so, it redefines element as the HTML object itself, instead of the string id.

Here's how you might use it:
// Create an element and append to the DOM
var myElement = document.createElement('div');
myElement.style.backgroundColor = '#00FF40'; // green
myElement.setAttribute('id', 'greenbox');
document.body.appendChild(myElement);

// Hide the element using a direct object reference
hideElement(myElement);

// Hide the element using the string id
hideElement('greenbox');
This is pretty rudimentary, and certainly doesn't allow for code reuse. Each time you want to overload a method, you have to do all these type checks using the typeof keyword. Not the ideal solution, but workable if you are just overloading a method with one or two type signatures.

JS Method Overloading: Making it reusable

Working from the end back, an ideal solution would be to have a simple utility function to add methods along with their type signature. Something like this:
function addMethod(obj, name, method, signature) {
   // implementation details
}

obj .......... we add the method to this object
name ......... the name of the method
method ....... the method to be added
signature .... the signature of the method, e.g. ["string", "boolean", "number"]
It turns out that someone already came up with this! In November 2007, John Resig wrote a post on JavaScript method overloading that contains a version of this very function. However, although his version is useful and very clever, it does not take into account overloading by type. It only allows overloading based on a different number of arguments.

Let's try implementing the addMethod() function now. Warning, this attempt fails (so don't copy from the code below, because it won't work) -- but it's educational to see the process of developing the code, so I've left this example in:
function addMethod(obj, name, method, signature) {

    // we will use this variable to check if a method already exists 
    // with the same name

   var existingMethod; 
   
   if (typeof obj[name] == 'function') { // if method already exists
        existingMethod = obj[name];      // store a reference to it
    }

    obj[name] = function(arguments) {        
        var signatureMatches = true;
        for (var i = 0; i < signature.length; i++) {
            if (signature[i] != typeof arguments[i]) signatureMatches = false;
        }

        if (signatureMatches) method((arguments);

        if (existingMethod) existingMethod(arguments);
    }
}
At first glance, this looks like it might work, but alas, does not. It somehow overwrites the existing methods so it is not working correctly. But fret not, for there is a working solution. As they say, when you fail, try, try again.

Finally, a Working Solution

This solution may not be the most elegant, but it gets the job done. This is licensed under the MIT license so feel free to use it for your projects (per the terms of the license).
function addMethod(obj, name, method, signature) {
    // The first time addMethod() is called, define the method
    if (typeof obj[name] == 'undefined') {
        obj[name] = function() {
            for (var signatureString in obj.overloadedMethods[name].signatures) {
                var signatureArray = signatureString.split(",");
                
                var signatureMatches = true;                
                
                for (var i = 0; i < arguments.length; i++) {
                    if (typeof arguments[i] != typeof signatureArray[i]) signatureMatches = false;
                }            
                
                if (signatureMatches) {
                    obj.overloadedMethods[name].signatures[signatureString](arguments);
                }

            }
        }
    }

    // The first time addMethod() is called, create overloadedMethods property
    if (typeof obj.overloadedMethods == 'undefined') {
        obj.overloadedMethods = {};
    }
    
    // The first time a method is added for a given name, create it
    if (typeof obj.overloadedMethods[name] == 'undefined') {
        obj.overloadedMethods[name] = {'signatures': {}};
    }
    
    // Store the method in an associative array (hash map)
    // keyed by the signature string, e.g. "number,boolean,array"
    obj.overloadedMethods[name].signatures[signature.toString()] = method;
}
This approach differs from the previous one in that I am saving an associative array of methods' signatures mapped to the method itself. Here are some tests which demonstrate how to use it:
// tests
var jonah = {};
addMethod(jonah, 'test', function(str) {alert("it's a string");}, ['string']);
addMethod(jonah, 'test', function(num) {alert("it's a number");}, ['number']);

jonah.test('string'); // alerts "its a string"
jonah.test(123); // alerts "it's a number"
The addMethod() function is actually only creating one method for "test", a method which iterates through the stored methods in the overloadedMethods object, checking the signature of each one. When it finds a match, it calls that method. Simple enough, I think.

Here's another example:
addMethod(jonah, 'test', function(bool, str) {alert("it's a boolean, and string");}, ['boolean', 'string']);

jonah.test(true); // this should do nothing
jonah.test(true, "this should work");
There is definitely room for improvement to this code. For one, you can break out of the outer for() loop once finding a match to save some cycles.

Another optimization is perhaps rewriting the way it finds the match. But I'll leave these for the topic of another article. Comments are welcome. Feel free to post your own improvements to the code, or alternate solutions.

Labels: