One big reason why the iPad matters…

Yesterday Apple announced the iPad, finally bringing an end to months of rumours. If you somehow missed all the hype, you can catch Steve Jobs’ keynote presentation here.

The response to the iPad has been predictable. Apple’s fans are crazy for it, while their detractors are falling over themselves to find fault with it. Is the device perfect? Certainly not. Either was the iPhone, but that didn’t stop over 40 million people from buying it, or stop tens of thousands of developers from contributing over 140000 apps to the platform. Apple currently owns the smartphone market, not because they produced the clearest sounding phone or the most powerful mobile email client, but because they created the best mobile user experience. The iPad promises a similar experience, with the benefit of a larger screen.

The large screen is the whole point of this device. Small devices like the iPhone are wonderful for personal use, but they don’t make it easy to share your content with others. They also don’t support truly rich user interfaces. Before you point out that your laptop handles those things nicely (one of the most frequent arguments against the iPad), stop for a moment to consider what you have to do to get information into it and out of it.

Your laptop is married to input technology that is over 30 years old. The QWERY keyboard and mouse/trackpad don’t exist because they represent the best way to accomplish their respective tasks. They exist because, several decades ago, they were the only practical solutions. Apple clearly recognizes that past necessity is a bad reason to continue doing anything, and the iPad is the first big step towards freeing users and developers from the limitations presented by these devices. Once app developers get their hands on actual devices, expect to find yourself using fewer traditional input methods and more innovative, human-friendly gestures. We don’t know exactly what these gestures will be yet, but the potential is there for the first time.

Multitouch technology married to a screen with decent real estate is a big deal for usability and accessibility. Anybody who can’t see that should think a little less about how they worked yesterday, and more about how they want to work tomorrow.

Update:

Steven F. does a better job of explaining this than me. Read his take on the iPad and the future of computing.

If you’re constantly disappointed by minor flaws in new technology, like a lot of people seem to be, you should probably read this.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to MySpace Post to Ping.fm Post to Reddit Post to StumbleUpon

Using Custom Objects in JavaScript

Objects provide a simple, powerful way to store and manipulate data, and should be part of every JavaScript developer’s toolkit. This short tutorial will demonstrate how to create custom objects for your data.

Note: This is not an in-depth tutorial. You should already be comfortable with basic JavaScript and programming concepts like functions and arrays before you start.

Start by examining the code in example 1:

Example 1: albuminfo.js

// Object definitions: function albumObject(theTitle, theArtistFirstName, theArtistLastName, theLabel, releaseYear, tracksArray) { this.title = theTitle; this.artistFirstName = theArtistFirstName; this.artistLastName = theArtistLastName; this.label = theLabel; this.year = releaseYear; this.tracks = tracksArray; this.artist = function() { return this.artistFirstName + " " + this.artistLastName; } } function trackObject(theTitle, theComposerFirstName, theComposerLastName, trackLength, personnelArray) { this.title = theTitle; this.composerFirstName = theComposerFirstName; this.composerLastName = theComposerLastName; this.time = trackLength; this.personnel = personnelArray; this.composer = function() { return this.composerFirstName + " " + this.composerLastName; } } function personnelObject(theFirstName, theLastName, theInstrument) { this.firstName = theFirstName; this.lastName = theLastName; this.instrument = theInstrument; this.credit = function() { return this.firstName + " " + this.lastName + " - " + this.instrument; } } // Function definitions: function albumPersonnel() { var allPersonnel = new Array(); allPersonnel['Davis'] = new personnelObject( "Miles", "Davis", "Trumpet"); allPersonnel["Shorter"] = new personnelObject( "Wayne", "Shoter", "Tenor Saxophone"); allPersonnel["Hancock"] = new personnelObject( "Herbie", "Hancock", "Piano & Electric Piano"); allPersonnel["Corea"] = new personnelObject( "Chick", "Corea", "Electric Piano"); allPersonnel["Carter"] = new personnelObject( "Ron", "Carter", "Bass"); allPersonnel["Holland"] = new personnelObject( "Dave", "Holland", "Bass"); allPersonnel["Williams"] = new personnelObject( "Tony", "Williams", "Drums"); return allPersonnel; } function personnelSideA() { allPersonnel = albumPersonnel(); personnel = new Array(); personnel[0] = allPersonnel["Davis"]; personnel[1] = allPersonnel["Shorter"]; personnel[2] = allPersonnel["Hancock"]; personnel[3] = allPersonnel["Carter"]; personnel[4] = allPersonnel["Williams"]; return personnel; } function personnelSideB() { allPersonnel = albumPersonnel(); personnel = new Array(); personnel[0] = allPersonnel["Davis"]; personnel[1] = allPersonnel["Shorter"]; personnel[2] = allPersonnel["Hancock"]; personnel[3] = allPersonnel["Corea"]; personnel[4] = allPersonnel["Holland"]; personnel[5] = allPersonnel["Williams"]; return personnel; } function trackList() { personnelA = personnelSideA(); personnelB = personnelSideB(); tracks = new Array(); tracks[0] = new trackObject( "Water Babies", "Wayne", "Shorter", "5:06", personnelA); tracks[1] = new trackObject( "Capricorn", "Wayne", "Shorter", "8:27", personnelA); tracks[2] = new trackObject( "Sweet Pea", "Wayne", "Shorter", "7:59", personnelA); tracks[3] = new trackObject( "Two Faced", "Wayne", "Shorter", "18:01", personnelB); tracks[4] = new trackObject( "Dual Mr. Anthony Tillmon Williams Process", "Miles", "Davis", "13:20", personnelB); tracks[5] = new trackObject( "Splash", "Miles", "Davis", "10:05", personnelB); return tracks; } function albumInfo() { var album = new albumObject( "Water Babies", "Miles", "Davis", "Columbia", "1976", trackList()); return album; } function printAlbum() { album = albumInfo(); var htmlOutput = ""; htmlOutput += "<p>"; htmlOutput += "<span>Title: " + album.title + "</span><br />"; htmlOutput += "<span>Artist: " + album.artist() + "</span><br />"; htmlOutput += "<span>Label: " + album.label + "</span><br />"; htmlOutput += "<span>Year: " + album.year + "</span><br />"; htmlOutput += "</p>"; // Loop through the tracks: for (var i = 0; i < album.tracks.length; i++) { htmlOutput += "<p>"; htmlOutput += "<span>Track " + (i+1) + ":</span><br />"; htmlOutput += "<span>Title: " + album.tracks[i].title + "</span><br />"; htmlOutput += "<span>Composer: " + album.tracks[i].composer() + "</span><br />"; htmlOutput += "<span>Time: " + album.tracks[i].time + "</span><br />"; // Loop through the personnel listings for the current track: for (var n = 0; n < album.tracks[i].personnel.length; n++) { htmlOutput += "<span>" + album.tracks[i].personnel[n].credit() + "</span><br />"; } // End personnel loop. htmlOutput += "</p>"; } // End tracks loop. document.write(htmlOutput); // Write the album info to the page. } // End function printAlbum. // Implementation: window.onload = printAlbum; // Call the printAlbum function when the page has finished loading.

There is a lot going on here, so let’s dig deeper and see what it all does.

Explaining Object Definitions

The first three functions are object definitions. These serve as templates for the information you will store and manipulate. Object definitions look a lot like like regular functions. You pass data to the object definition the same way you would pass values to a function, then create properties to store it.

A property definition looks like this:

this.theProperty = theData;

In the above, this refers to the object itself, theProperty is the name of the property, and theData is data that was passed to the object definition. Properties can store simple values, like strings and numbers, arrays, or even other objects.

You access properties like this:

var result = theObject.theProperty;

Properties can also represent functions. This allows you to create objects that can perform complex (or not so complex) operations on their own data, and return a result. Look at the albumObject() definition in example 1. The artist property represents a function that compiles the artist’s first and last names into a single string, with a space between the names. Similar functions are used in the trackObject and personnelObject definitions to make it easier to access full names. Remember that whenever you access a property that represents a function, you have to include the brackets at the end of the function name:

var result = theObject.theFunction();

Implementation

Now that we have taken a quick overview of object definitions, let’s work backwards though the rest of the code to see how it works. The implementation line is very simple:

window.onload = printAlbum;

This calls the printAlbum function when the window has finished loading. The first line of the printAlbum function creates a variable called album to store the result of the albumInfo function.

The albumInfo function simply creates and returns a new albumObject object. Notice that the last argument passed to the new object is a call to the trackList function. The result of this function call will be stored in the tracks property.

The trackList function returns an array of trackObject objects, which contain information about the album’s tracks. The first two lines of the trackList function are calls to the personnelSideA and personnelSideB functions, which return arrays of personnelObject objects. Each instance of personnelObject contains the name and role of a different contributor. The personnelSideA and personnelSideB functions both call the allPersonnel, which creates all the personnelObject objects for the entire album.

Turning our attention back to the printAlbum function, we can summarize the album object as follows:

  • 1. The album object is an instance of albumObject, and stores general information about the album.
  • 2. The album object contains a property called tracks, which stores an array of trackObject objects.
  • 3. Each instance of trackObject contains a property called personnel, which stores an array of personnelObject objects.

The remainder of the printAlbum function writes the contents of the album object to the document. Example 2 shows the result.

Title: Water Babies
Artist: Miles Davis
Label: Columbia
Year: 1976

Track 1:
Title: Water Babies
Composer: Wayne Shorter
Time: 5:06
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Ron Carter – Bass
Tony Williams – Drums

Track 2:
Title: Capricorn
Composer: Wayne Shorter
Time: 8:27
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Ron Carter – Bass
Tony Williams – Drums

Track 3:
Title: Sweet Pea
Composer: Wayne Shorter
Time: 7:59
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Ron Carter – Bass
Tony Williams – Drums

Track 4:
Title: Two Faced
Composer: Wayne Shorter
Time: 18:01
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Chick Corea – Electric Piano
Dave Holland – Bass
Tony Williams – Drums

Track 5:
Title: Dual Mr. Anthony Tillmon Williams Process
Composer: Miles Davis
Time: 13:20
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Chick Corea – Electric Piano
Dave Holland – Bass
Tony Williams – Drums

Track 6:
Title: Splash
Composer: Miles Davis
Time: 10:05
Miles Davis – Trumpet
Wayne Shoter – Tenor Saxophone
Herbie Hancock – Piano & Electric Piano
Chick Corea – Electric Piano
Dave Holland – Bass
Tony Williams – Drums

If you want to try the script for yourself, you’ll need to reference it from an HTML document. Example 3 provides a basic one that will do the trick.

Example 3: albuminfo.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script type="text/javascript" src="albuminfo.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Album Info</title> </head> <body> </body> </html>

Wrapping Up

There we have it! All that data is wrapped up in one little object, easily accessible whenever we need it. The usefulness of custom objects goes beyond static data storage. For example, I use them to track users’ mouse clicks and movements when designing complex user interfaces. By creating objects to represent each element on a page, I can independently track which objects have been clicked and change their state or appearance accordingly. Custom objects can take a lot of the pain out of JavaScript programming, and make your scripts more efficient at the same time.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to MySpace Post to Ping.fm Post to Reddit Post to StumbleUpon

Win a free Taxulator!
Taxulator Icon
App_Store_Badge_EN

Want to win a free Taxulator for your iPhone or iPod Touch? Here’s how to enter in two easy steps:

1. Follow @heuristicmedia on Twitter.
2. Tweet the following text, or something similar. Don’t forget the #Taxulator hashtag, or we might not see your tweet!

I just entered to win a free #Taxulator for #iPhone! Visit http://bit.ly/FreeTaxulator to enter. Please RT!

Ten winners will be chosen at random from all valid entries received before 12:00AM EST, November 30, 2009. Enter as often as you want, but please try not to annoy your followers! :-)

Due to App Store limitations, this contest is only open to entrants who have a U.S. iTunes account.

Click here to learn more about Taxulator

Thanks for participating, and good luck!

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to MySpace Post to Ping.fm Post to Reddit Post to StumbleUpon

Taxulator 1.2 Sneak Preview!

Update – August 27, 2009: Taxulator 1.2 is now available from the App Store!

Taxulator 1.2 has been submitted to the App Store. This free update will introduce a completely new user interface. Here is a sneak preview!


Taxulator Main View

Taxulator Main View


Taxulator Main View (Reverse Mode)

Taxulator Main View (Reverse Mode)


Taxulator Settings View

Taxulator Settings View


Taxulator 1.1 links:

About Taxulator 1.1
Taxulator 1.1 video
Buy Taxulator 1.1

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to MySpace Post to Ping.fm Post to Reddit Post to StumbleUpon

Taxulator Review at The Loop

Taxulator just received a positive review by Jim Dalrymple at The Loop! Read the review

Jim suggested that the tax settings panel should be moved into the app, instead of the iPhone settings bundle where it currently resides. A number of Taxulator users have asked for this change and it will be implemented in the next update.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to MySpace Post to Ping.fm Post to Reddit Post to StumbleUpon