jQuery Form and jQuery UI Tabs: Two great tastes that taste great together

I spent last week holed up writing part 4 of Ajax Overhaul, my series of articles for IBM developerWorks. Aimed squarely at Ajax beginners, the series shows how to progressively enhance Web 1.0 sites with jQuery and Ajax. Each installment starts with the pre-Ajax version of an example e-commerce application and takes readers through the steps of retrofitting it to improve and modernize the user experience. The tagline for this installment is "Streamline multi-step processes with tabs and Ajax forms," a topic that allowed me to employ two of my favorite plug-ins for the jQuery open-source Ajax toolkit:

  • jQuery Form, which gives jQuery several methods for serializing form data and submitting the results via Ajax.
  • jQuery UI Tabs, which turns a series of divs and unordered lists into a tabbed interface.

I feel like I've run on and on about my enthusiasm for jQuery on this site, but I can't help it. One of the cool thing about its plugin ecosystem is the ease with which you can cross-pollinate a couple of plugins to create novel effects. In this case, I wanted to take a series of web forms - the checkout process for my example shopping site - and turn them into a single-page, tabbed interface in which each tab represented one step of the process. The biggest additional requirement was progressive enhancement; with JavaScript absent or disabled, the checkout process has to work like it did before I retrofitted it. All it took to accomplish these goals was a judicious mix of my two plugins.

Exampleshoppingapp

Continue reading "jQuery Form and jQuery UI Tabs: Two great tastes that taste great together" »

Grails and JSONP: How Easy is That?

Grails_logo For all of those Java developers casting longing glances at their buddies doing Rails development, there is hope. Grails, which has just celebrated its 1.0 release, is a Rails-like "convention over configuration" framework that aims to do for the Java world what Rails has done for Ruby. Instead of Ruby, the dynamic programming language of choice is Groovy, which compiles to bytecode (no Groovy to Java translation) and integrates smoothly with just about any Java code you may be using.

I'll stop hyping Groovy and Grails in general here; there's plenty of good informational stuff on the Grails and Groovy home pages. I will note that if you run off the tracks a little bit, you can find yourself reading through 500-odd line stack traces of Groovy, Spring and Hibernate -- there's room for some improvement there.

One of the many nice things about Grails is it's support for JSON and XML. Let me put together a simple example that shows off some of Grails' power.

Continue reading "Grails and JSONP: How Easy is That?" »

Bjax: Make it Play MP3's

It's nice to know you've inspired someone and it was very nice of Chris Anderson to drop us a note on his own Bookmarklet: Make it Play. Basically, this bookmarklet will scan a page for mp3 links and then insert a little semi-transparent media player interface at the bottom of the page.

It's not SongBird, but it's a good demonstration of the power of Bjax -- injecting user interface to improve an existing web interface. Based on JQuery.

Technorati Tags: , , , ,

Ajax Intervention: Comcast.com

Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.

Up this time: Comcast.com, which, despite an extremely "Web 2.0" look and feel, misses the mark with its Ajax features.

Comcast is one of those companies everybody loves to hate. Yet a quick glance at the latest version of the big cable operator's web presence reveals some surprisingly up-to-date visual motifs. With its easy-to-read text, expansive white space, candy-colored visual palette and simple calls to action, Comcast is far more modern-looking than its competitors. Time Warner Cable, DirecTV and Dish Network all offer cramped, console-style interfaces that wouldn't have looked out of place five years ago. But Comcast is clearly looking to incorporate the look and feel of Web 2.0.

Comcast0_2

Disclaimer: I'm a customer of Comcast and DirecTV but not of Dish Network or Time Warner, so I'm can't speak about the password-protected areas of the latter sites. Comcast's homepage is fairly similar to the other sites', but the rest of comcast.com looks strikingly different from your typical sales-and-service site.

Or so it appears. Once you actually click around the Comcast site, it becomes clear that most of its freshness is merely visual. The functionality and user experience are just as inconsistent as we've come to expect from big corporate sites.

Problem: Wonky Login Module

The site includes two login modules: A traditional one on the homepage and an Ajax one elsewhere. When entering bad credentials into the homepage one, you get redirected to the standalone one, where a loading icon indicates an in-progress XHR. Sometimes, that XHR hangs ... forever. No graceful failure message ever appears. During the site's relatively frequent performance slowdowns, even correct login credentials can result in a permanently hanging Ajax call. That tends to confuse users. The validation scheme is even more confusing. Blank required fields earn you a JavaScript alert box, while errors from the server side get loaded via XHR into into the markup.

Comcast1 Comcast1

Solutions

  • Provide graceful failure for your asynchronous requests by setting a timeout on them. The XHR object doesn't offer this natively, but most popular libraries do.
  • Use a consistent DHTML error-reporting framework rather than a grab bag of alerts and inline messaging. In addition to being more user-friendly, it will be easier to maintain.
  • Build reusable components and, if necessary, style them differently on different pages. Don't build two overlapping components with strange dependencies.

Problem: Inconsistent Shopping Cart

When you visit the Comcast.com to shop for new service, the shopping cart utilizes a strange mixture of DHTML, Ajax, popups and traditional navigation to guide you through the process. On the first page view, before you've even added any services, a loading icon signals that an Ajax call is in progress. As it turns out, they're making an XHR just to load an empty shopping cart. As you add services from multiple tabs, Ajax is again used to update the shopping cart. But to remove items from the cart, you must click an "edit" button and do so in a popup window.

Most puzzlingly, the interface doesn't seem to validate your choices. I was able to add separate phone, cable and internet products to my cart, then add a bundled "Triple Play" phone/internet/cable package. I went very far down the checkout funnel without ever receiving a notification that I was ordering an incompatible array of products. Yet when I cleared out the cart and just played around with the standalone cable products, the interface kept me from breaking the rules. If I added cable package A, then added the mutually exclusive package B, package A disappeared from my cart. Yet there was no messaging to explain what had happened.

Comcast1 Comcast1 Comcast1

Solutions

  • Don't use Ajax for just one aspect of your component. If the user can add items inline, she should be able to remove them, too.
  • Let your users know what's going on. If you're going to use validation logic to remove things from their cart automatically, then message them when you've done so.
  • Model your GUI widgets on traditional form controls. Mutually exclusive options should behave like radio buttons; a la carte ones, like checkboxes. A laundry list of options, some a la carte and some mutually exclusive, is usually a bad idea. Group each set of logically related options into something resembling a fieldset.

Problem: Inconsistent Global Navigation

Once you're past the homepage, with its left nav column, comcast.com presents you with a consistent top nav bar: Learn, Shop, Programming, Customers, About, and a search box. But the tabs themselves aren't clickable; you have to drill down within the DHTML menus to select a specific topic. Certain topics inexplicably load new windows, often from separate subdomains, full of Flash or HTML content. The navigation on these windows is different from the main site - or totally absent.

Solutions

  • Study basic usability. The tabbed navigation metaphor has been around for ages. Follow best practices when implementing it.
  • Consolidate your content. If you can embed a Flash movie in a popup window, you can embed it in your main window. It's jarring for users to be sent off-site without warning.
  • Don't disorient your users. Your navigation doesn't need to be identical in every sub-domain, but do at least provide a consistent way to navigate back to the homepage.

Problem: Slavishly Consistent Color-Coding

Each section has its own design scheme in which headlines, buttons, links and tabs all appear in the same color. Links aren't even underlined. It's therefore impossible to tell, without mousing over an element, whether or not it's clickable. Users often have to play target practice and click on a small "go" link to get to a subsection; the headlines themselves are inconsistently clickable.

Comcast1

Solutions

  • Underline your links and make buttons look like buttons. UI design isn't art; it's science. Users know the rules and get annoyed when you break them.
  • If you must abandon underlined links, then do something to differentiate your links from other content. A pretty color palette is useless if it causes users to click continually on the wrong elements.
  • When in doubt, make it clickable. Don't just link a button when you can link the accompanying image and/or headline, too.

Problem: JavaScript Users Only

If you visit comcast.com with a JavaScript-disabled browser, almost nothing works. There's not even an old-school "please turn on JavaScript."

Solutions

  • It's 2007. Follow web standards. Use progressive enhancement. If you're not building a cutting-edge RIA with heavy client/server data exchange, there's no reason to require JavaScript. At the very least, inform your users that their browser isn't supported.

Conclusions

Most large corporate sites can't retool themselves overnight. At best, they can update their features one at a time and use fresh visual approaches to call out their new interactivity. But in doing so, they should rely on old-fashioned user exerience design, follow industry-standard UI conventions and strive for a consistent experience. Comcast's bright, big, bold design scheme is a welcome development, but it's only the first step in what could be a comprehensive UI redesign.

Technorati Tags

Ajax Intervention: Product tooltips in Amazon's beta redesign

Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.

Up this time: Amazon.com and its inconsistent new Ajax redesign.

The beta test for Amazon's new DHTML navigation has garnered plenty of perceptive commentary from the Ajax and UxD communities. (See posts from Ajaxian, Functioning Form, Jeffrey McManus and CommaDot.) Yet one puzzling bit of Ajax fuctionality hasn't gotten much notice: The inconsistent use of tooltips in item listings.

I've long bemoaned the fact that Amazon doesn't let me add an item to my cart, or to my wish list, from its search results and landing pages. To buy an item, I've always had to navigate to the item's individual product-details page. But that's all changed with the new redesign - sort of.

Homepage

When I visit the new Amazon homepage, I see a module titled "What Do Customers Buy After Viewing This Item?" It contains thumbnails and headlines for three different products related to my most recent search. Next to the name of each product, I see a little blue caret graphic. Mousing over it, I'm presented with an extremely useful microcontent popup with some basic product details and two buttons: "Add to Cart" and "Add to Wish List." I've longed for just such a feature for years. It's as if Amazon has finally read my mind.

Whatdobuy

But ... wait a minute. Directly above and below the "What Do Customers Buy ..." module, I see two similar modules: "New For You" and "More to Explore." The former contains product suggestions; the latter, products I've previously viewed, or items similar to them. But both sets of listings lack the little blue caret graphic for which I've now been trained to look. I try to mouse over various portions of each listing, but no tooltip appears. For these products, I guess I still need to navigate to a details page to purchase them.

Newforyou

Moretoexplore

How about the search results page? A quick search for "Cory Doctorow," my new favorite sci-fi writer, returns three pages of results. The very first item is the one I'm looking for: the short-story collection "Overclocked: Stories of the Future Present." Once again, Amazon is reading my mind. But try as I might, I can't find a tooltip or an "Add to Cart" button. Once again, I'm forced to load an entire new page - with several scrolls worth of extraneous data - just to purchase something I've already decided I want. This isn't so bad when I visit the site to search for a single item. But how about those times when I come with a list of 10 new tech manuals to purchase? The number of pages I need to load is twice what it should be. God forbid I don't have broadband.

I understand why this sort of thing happens on big sites. Amazon runs tons of betas, often simultaneously, to gauge the effectiveness of individual UI tweaks based on rigorous metrics. Interface refinement is about testing new ideas without re-architecting your entire site or totally confusing your existing user base. I have no doubt that the search-results page and the three upsell modules I'm testing are all maintained separately, perhaps by separate teams. If the Ajax functionality in one of them proves successful, it will eventually make its way to the others.

Still, in the meantime, users are left with a UI whose inconsistency casts doubts about the validity of any data it generates. How can a new feature win over your users if it's applied arbitrarily?

Ironically though, unliike most of Amazon's little DHTML/Ajax tweaks, I think this one is executed almost flawlessly. You can barely see it on a fast connection, but there's a nice little animated "loading" bar graph to provide status on your XHR. The telescope effect on the tooltip itself is subtle but nice. I might quibble about the rendering logic, which allows the tooltip to scroll off the page rather than shifting it fully within the viewport. Still, I know how difficult that logic can be to pull off on a templatized, highly dynamic site. Overall, this is an extremely well though-out feature that should make it faster and easier for customers to drop some cash. Let's hope it makes it onto the entire site.

Technorati Tags

Ajax Intervention: Tivo.com online scheduling

Welcome to Ajax Intervention, in which we dissect how major websites misuse, or fail to use, Ajax to improve their user experience.

Up this time: Tivo's My Tivo online scheduling tool, which could use an emergency Ajax intervention.

As much as I love my Tivo digital video recorder, it's no fun to schedule recordings on a television screen with a remote-control joystick and a virtual keyboard. But thanks to a wireless card and the online My Tivo service, I can schedule a program from any web browser as little as an hour before it's set to air. The service was originally billed as a tool for last-minute scheduling when you're away from home, but I use it even when I'm sitting in the same room as my DVR. Web interfaces are just easier than Tivo's on-screen menus.

That said, the My Tivo interface could use an update. Given the small number of ads that appear on the site - most of them 120x120 buttons with shallow inventory - it's hard to imagine Tivo is earning much money from all the extra pages its users are forced to navigate just to schedule a Season Pass of their favorite show. The process goes something like this:

  • Visit the "Online Scheduling" page in My Tivo.
  • Enter a program in the search box.
  • Receive a results page.
  • Click on a show's title.
  • Receive a program details page.
  • Click "Get a Season Pass."
  • Receive the recording-options page.
  • Choose your recording options.
  • Receive a confirmation page with no compelling content.
Picture_1_2 Picture_2_2 Picture_3 Picture_6 Picture_4 Picture_5

That's a minimum of five full pageloads just to schedule one program, without a bit of Web 2.0 goodness in sight. Sure, there are some DHTML tabs at the bottom of the program details page. But that's about it.

I'm not just talking about the lack of Ajax, either. The Tivo set-top box is all about personalization; based on your ratings of shows you've recorded, it can predict which shows you might like and predictively record these "Tivo Suggestions" for you. But any such personalization is buried in the Tivo web interface, inside a DHTML tab at the bottom of the program details page.

Click it and you'll learn, for instance, that lovers of "Buffy the Vampire Slayer" also enjoy "Angel," "Charmed" and "The X-Files." But there's nothing to suggest these canned recommendations are based on my own viewing habits; in fact, I've given "Charmed" the dreaded "three thumbs down" rating on my own Tivo box and it's still showing up here. Why on earth isn't this content specifically targeted to me? If the content were compelling, maybe it wouldn't deserve to be socked away inside a tab.

Now let's imagine how My Tivo might look with an Ajax overhaul and better personalization.

  • Visit the "Online Scheduling" page in My Tivo.
  • Enter a program in the search box.
  • Thanks to Ajax autosuggest, receive an inline list of the most likely matches. Click on the one you want.
  • Receive a program details page.
  • Click "Get a Season Pass."
  • Thanks to the power of Ajax, receive a lightboxed recording-options dialogue and choose your options without leaving the page.
  • Within the same lightbox, receive a confirmation message that includes personalized recommendations for additional shows.

By replacing three page refreshes with Ajax calls, we can reduce the process of scheduling a Season Pass down to two pages and, with better data mining on the server side, throw in personalized recommendations, too. If you've noticed that the UI I'm describing is a complete Netflix ripoff, well, duh. Why shouldn't Tivo - the company that invented the DVR market and then watched inferior operators eat away at its market share and profitability - take a page or two from the playbook of the company that's almost single-handedly decimating Blockbuster? Netflix operates like an Internet company, not an entertainment company. Tivo should follow suit.

Sure, Tivo continues to leverage wi-fi, desktop software and content partnerships into an impressive array of services. Its set-top boxes really can function as wireless entertainment hubs. But Tivo behaves, fundamentally, like a moribund hardware maker. It treats its web offerings like inferior adjuncts to the set-top experience, thereby neglecting a powerful means of product differentiation. And really, with the entire country laying odds on how long you'll stay afloat, shouldn't you pursue every possible avenue to improve your product?

Crappy cable-provider DVRs lack Tivo's intuitive UI and powerful wireless integration, but they're in a lot of homes thanks to competitive pricing and the marketing muscle of Comcast, et al. Meanwhile, true geeks can roll their own DVRs using commodity PC hardware and open-source software. Tivo's best hope for the future involves beating the cable companies on features and beating the DIY crowd on ease of use. A solid web UI would be a nice step in that direction.

Mash note: Remember the Milk

You've got to love a Web 2.0 startup manned by a dev team of 2 that manages to add every feature on your wish list just before said feature's omission really starts to bug you. That's the case with me and Remember the Milk, a to-do-list webapp developed by an Australian company and supplemented by awesome new features with astonishing regularity.

Although they're a commercial entity, they've got a beta API that's allowed the development of a handful of really cool mash-ups. They've had iCal integration and a gCal plug-in for ages. They got on the Twitter bandwagon really early. They were one of the first non-Google companies to port their application offline with Gears. Last but not least, they've got a powerful (though still not perfect) user interface. (More on that later.)

A little background: I've been an obsessive to-do-lister since high school. GTD is my mantra. During my years at Microsoft-centric companies, I used Outlook to manage my entire life. But these days I find myself on Windows, 'nix and OS X machines in disparate locations for hours or days at a time. A webapp is clearly the only way to go for my to-do needs. But after years as an Outlook power user, I need something that will slice and dice my many lists (work, play, home, shopping, whatever) with exacting precision.

I gave Apple's iCal a shot, but its list functionality was way too primitive. I need multiple lists, categories, tags, flexible sort criteria - you get the picture. Ta-Da Lists from 37signals was even more stripped-down than iCal - plus I found its interface surprisingly clunky for something developed by a well-regarded Ajax shop. I thought about todo.txt, but I'm not enough of a command-line purist to completely abandon the GUI - even after years of suffering through Outlook's hideous hidden menus. Then, about a year ago, I stumbled on Frank Gruber's Do More: Online To Do Lists Compared. I didn't agree with his conclusions, but at least he gave me several more options to explore. Luckily for me, Remember the Milk was the first one I tried.

There's a lot to love about RTM, especially its UI, so just let me gush for a minute.

  • Flexible organization: You can create multiple tabbed lists, apply arbitrary tags to your tasks, and create saved searches based on any criteria.
  • Keyboard navigation: Except for a few advanced functions, such as moving items from one list to another, you can do almost anything from the keyboard. Create tasks, set priorities and due dates, apply tags, edit multiple items ... most functions take only a single keystroke.
  • Natural language entry: You can set due dates and repeat intervals using some pretty flexible natural language. It ain't perfect, but with a little training the syntax becomes second nature.
  • SMS, IM and email reminders: The service can nag you quite effectively via a wide range of communication protocols.
  • Email, gCal, Atom and Twitter integration: You can create tasks or lists of tasks using a special email address; add or edit tasks directly from gCal and Yahoo plug-ins; and use Twitter or Atom as syndication services. The public API means that mash-ups and cross-pollination will only proliferate.
  • Built-in collaboration capabilities: There are a host of features dedicated to assigning, sharing and collaborating on tasks.
  • Serious accessibility: The main app is fast, powerful Ajax all the way, but the mobile version works just as well in a variety of more specialized user-agents.

There are a few things to hate:

  • Poor multi-list view: The main Overview page list all of your tasks that are due, overdue or due tomorrow regardless of which list they're on. But it separates the Today, Tomorrow and Overdue tasks into separate tabs. The gCal plug-in does a much better job of showing all of your most important uncompleted tasks in a single, unified view.
  • Recurring task weirdness: Delete a completed instance of a recurring task, and you've just deleted the master version of that task. After any previously spawned instances are completed, the task will no longer recur. This is a very strange user experience, especially for folks who like to purge their completed tasks every once in a while.
  • Poor sortability: Tasks are sorted by their priority. Period. This shortcoming doesn't account for the fact that a low-priority task that's a week overdue is probably a high-priority task by now.

See the strikethrough text above to see exactly what I meant about the RTM team rolling out your must-have features before the lack thereof becomes too annoying. I've been dying for flexible sortability on RTM since I started using it. But no sooner did I start this post than I noticed an RTM blog post announcing just such a feature. It would be nice if you could set your sort preference globally as well as one list at a time, but that's a minor quibble.

So what can we learn from my ramblings, besides the fact that I really, really love this platform? I think there are a few powerful lessons for developers of any RIA:

  • You don't have to sacrifice brawn for the sake of simplicity: Pleasing power users doesn't mean hopelessly confusing everybody else - at least not with smart UxD. (Apple could stand to learn that lesson, but I digress.)
  • You don't have to sacrifice accessibility in the name of Ajax: Let your mobile app function as your accessible app, too.
  • You don't have to fear Web 2.0 trendiness: Rapid adoption of emerging protocols such as Twitter can only help you differentiate your product and find new users.
  • You don't have to lock your app down, even if you're a commercial enterprise: Public APIs - and the cross-pollination they enable - can only strengthen your foothold in the marketplace. In our Googlized world, this one's kind of a *duh*, but it bears repeating.
  • You don't have to hide from your users: An active blog and well-maintained user forums are far more powerful marketing tools than terse release notes on Google Code.

I can only speculate as to the future of GTD's business model or exit strategy. Their logo carries the ubiquitous "Beta" tag, and their pages carry no ads. Where's the funding? It seems like somebody's waiting to get snapped up by a big player....

Lord knows it would be nice to have the old  Outlook/Palm OS quintet of email, calendar, contacts, notes and to-do lists available on a single web-based platform; personally, I would prefer that platform to be Google, though I can't really see them acquiring a start-up just for this one capability. Still, it would be a shame if a product as solid as Remember the Milk got lost in the shuffle or edged out by inferior offerings from bigger players. Only time will tell....

SOA meets Ajax - APIlitAx: an Alternative Interface for Google AdWords

In the deluge of social bookmarking, weather ticker, and notepad applications, it's always nice to see an application come along that isn't a toy. APIlitAx (ugly name, I know) is an alternative interface to the Google AdWords system. It seems to have been developed by some folks at google and has been released on Sourceforge. As an application, it is very different from most of the stuff coming out of Google these days, which seems focused around the GWT technology. This applications doesn't use an existing Javascript framework, i.e. it's all custom Javascript, and uses PHP on the back end to proxy requests to AdWords via the APIlity library (PHP API for AdWords).

screenshotCampaignView.png

The developers have been careful to make the application non-blocking, i.e. you can interact with parts of the interface while another part updates. This is probably an emerging best practice for Ajax apps: don't just make lots of small blocking requests. Design your apps so that you can make small, non-blocking requests.

Technorati : , , , ,

The Bonehead File - NewsIsFree Newsmap

A friend of mine pointed me at this "nifty Ajax news map" from Newsisfree. These guys have been doing stuff with RSS for a long time. If you needed an RSS feed for a publication that was so behind the times that it didn't have one, Newsisfree gave it to you. At a first glance, it looked pretty slick, with sliders, drop downs, pop-up windows and the ability to change both the language and category you're looking at, all without reloading the page.

www.newsisfree.com_newsmap.png

So I settled in to investigate. Half the fun in reviewing all of these Ajax applications is in figuring out how they work. My tool of choice for this is the Firefox extension Firebug, the "view source" of the Ajax age. (Face it, these days if you do a literal "view source," you'll have no idea of what's going on.) After loading up the news map, I popped up the debugger and took a quick glance at what JavaScript files were included. At first glance it looked promising: there were prototype.js and moo.fx.js. I prepared myself mentally for some heavy Ajax lifting.

Next some bad news. I noticed a message in the status bar that said "Applet HoneycombLoader started." What a downer, I thought, but then again people are combining Ajax and flash so why not Ajax and applet's? A few more moments of investigation revealed the awful truth: the only Ajax on this page was triggered by the two select boxes at the top -- one for category the other for language. The actual Ajax bit was a request to a PHP script that returned a JSON object that contained a URL. This URL was then used to change the content of the IFrame that held the applet. That's it. Here's the callback that does the business:

function getMapProcess(Request)
{
 lightWin.hide();
 try { var res = eval('('+Request.responseText+')') }
 catch(e) { return hpe.error(e) }
 if (res.response_code>=300) {
    alert("Failed to generate map");
 } else {
    var f = $('mapcontainer');
    f.src = res.htmlfile;
 }
}

This static information could have simply been hardcoded in a JavaScript lookup table and used to change the contents of that IFrame. All that the XHR did was move that static lookup table to a PHP script on the server. All those slider and popups were part of the applet.

I hope this little bit of superfluous Ajax wasn't used to sell the product. Maybe I shouldn't be so bothered about it, but I was so looking forward to analyzing its workings. It's still and interesting app, though; it just doesn't really have anything to do with Ajax.

Technorati : ,

Using Bookmarklets to Disruptive Effect

But any big change is more likely to result if there is a disruptive event such as new technologies or platforms that have a surprising effect on market share. -- Trip Hawkins

My consulting company is relatively small, so I love disruptive technologies. I see them as opportunities to sneak up on the big boys. I suppose that if I were one of the big boys, I wouldn't be so enthusiastic about disruptive technology. But there it is. Bookmarklets and Greasmonkey are just such disruptive technologies. They let you create mashups and manipulate pages in ways that were not intended by the original authors. They are a way to make content and sites work better for you.

While Greasemonkey lets you automatically execute scripts after page has loaded and allows you to make XHR requests to other domains, it requires a user to install a plug-in that isn't easily available for all browsers. Bookmarklets, on the other hand, are as easy to install as a bookmark, but they require a user to click or select a bookmark in order to work.

Last time, we saw how to load additional JavaScript into the browser in order to exceed the size limits of the bookmarklet itself. This time we're going to hack the front page of the New York Times with our own news. First, we need a bookmarklet that will load our actual script. We simply adapt our code from last time to load our nyt.js script.

javascript:(function(){var s,d=document,a=function(o){d.body.appendChild(o)};s=d.createElement('script');s.type='text/javascript';s.src='http://labs.pathf.com/bm101/nyt.js';a(s)})();

The code simply inserts a script element that points to our JavaScript file. You can see the live link below.

Drag the following link to your toolbar or bookmark it:
NYT Hack

If you now navigate to the New York Times home page and click on the link, you should be able to see some stories about Iraq inserted above the fold.

nythack.jpg

How did I do this? Well, it's all about what I packed into that nyt.js file. What's in there? Well, first I added in JQuery, my favorite Javascript library of the moment. Since the New York Times site doesn't use Prototype or anything that declares a $ function, we don't have to take any special precautions. Next, I defined a utility function to load in a script from a URL:

// NYT Funcs

var NYTHack = new Object();

NYTHack.addScript = function(url) {
    var scr = document.createElement("script");
    scr.type = "text/javascript";
    scr.src = url;
    $("body").append(scr);
}

This is the same trick as earlier. Instead of performing an XHR, we inject Javascript which is executed withing the context of the current page. And what do we inject?

NYTHack.insertYahooNews = function() {
    // insert the yahoo news script tag with a callback
    NYTHack.addScript('http://api.search.yahoo.com/NewsSearchService/V1/newsSearch?appid=YahooDemo&query=iraq&results=5&language=en&output=json&callback=NYTHack.callBack');
}

// run me
$(document).ready(function(){
    NYTHack.insertYahooNews();
});

We load from Yahoo's News Search Service. Why Yahoo? Because they let you specify JSON as the output format and further specify a callback function, to which the JSON object is passed as a parameter. Our callback (along with a utility function) looks as follows:

NYTHack.buildStories = function(div, json) {
    var stories = json.ResultSet.Result;
    for (var i = 0; i < stories.length; i++) {
         div.innerHTML += '<h4><a href="' + stories[i].Url + '">' + stories[i].Title + '</a></h4><p>' + stories[i].Summary + '</p>';    }
}

NYTHack.callBack = function(json) {
    var div = document.createElement("div");
    div.id = 'nythack';
    div.style.border='1px solid #ff0000';
    div.style.padding='5px';
    var hl = document.createElement("h2");
    hl.innerHTML = "Iraq News from Yahoo!";
    div.appendChild(hl);
    NYTHack.buildStories(div, json);
    $("#mainTable").before(div);
}

Nothing fancy. We just pull titles, summaries and url's out of the JSON object and construct a set of headlines and links. Then we insert it ahead of the main content section of the NYT home page.

Now we don't do any error checking and you can run this bookmarklet in other pages than the NYT home page. Adding those in wouldn't have been too onerous, but it would have distracted from the main focus of the bookmarklet and cluttered the code. Ideally we would check in the bookmarklet itself to see whether we had already loaded it once by looking for a hidden div element with a particular id.

Next time we will actually use the information on the page to drive what our bookmarklet does and we will use the site itself as a web service using Sarissa.

    Technorati : , ,

Application Watch - Valoony: Ajax Enabled Comparison Shopping

The German comparison shopping site Valoony has launched three new Ajax enabled comparison shopping mini apps: one for digital cameras, another for perfume, and -- my favorite -- one for wine.

valoony.jpg


The interface allows you to adjust various numerical parameters using sliders, select brands, types and specific stores, and enter search terms, etc., all of which cause the right hand content panel to update via XHR. On Joe Walker's 4 States of Ajax Adoption, I'd say this is state #2 -- Progressive Enhancement. The interface still uses IFrames and more traditional pre-Ajax techniques. Also, you can easily get into a confused application state by using the browser's back button instead of the "Zurueck" button in the page.

From a user experience perspective, I'm not sure this particular use of Ajax improves my shopping experience or is something that couldn't have been done before with Javascript and IFrames. Then again, I don't know what the old shopping experience was like, so this may be a vast improvement. It's certainly much better than my last frustrated fumblings on CNet. Also, I got an excellent deal on a 1996 Brunello. ;-)

Technorati : ,

Bookmarklets 101

Today I want to build the "Hello World!" of bookmarklets. Actually, I'm going to build two versions, the second of which will allow us to do bigger and better things than the first. So, what exactly is a bookmarklet? It's a bookmark that points to javascript instead of a web page -- javascript:... instead of http:.... This Javascript then runs in the context of the current page -- sort of a Greasemonkey script that you invoke by clicking or selecting a bookmark.

If you're using Firefox, this is going to be a whole lot easier than if you're using IE, Opera or Safari. In Firefox, you can drag a link to your toolbar and have it easily available for use. In IE and Opera, you can bookmark the Javascript link and have it available in your bookmarks dropdown menu. As far as Safari goes, not all bookmarklets work in it -- as we'll find out, there's not really enough space in a bookmarklet to do much cross browser support --, but this won't really be a problem for us given this bookmarklet's code and the direction we are going with the second version.

OK, here's the first version. It's about a simple as it gets:

javascript:alert("Title: " + document.title);

You can try out this bookmarklet below.

Drag the following link to your toolbar or bookmark it:
Title

IE will complain (provided your system has the latest security patches) about adding an unsafe bookmark. Browse to a different page and select the bookmarklet and you will see that it correctly displays the page's title. So far so good.

What if we want to do something more substantial, say write a bookmarklet that would inspect the DOM of a page and modify it based on some sort of algorithm? Well, bookmarklets can only be so large -- no more than 255 characters in some older browsers, a few thousand characters in the case of the newer ones. If you're going to write bookmarklets that do interesting things, where are you going to put the code? One approach, is to use an Ajax technique known as DOM-based on-demand Javascript. That's just a fancy name for inserting a script element into the DOM of the current page. There are lots of bells and whistles we will add in future examples, but for the moment we will keep it simple.

The second version looks like this:

javascript:(function(){var s,d=document,a=function(o){d.body.appendChild(o)};s=d.createElement('script');s.type='text/javascript';s.src='http://labs.pathf.com/bm101/hello.js';a(s)})();

At the top level we are declaring an anonymous function and calling it, all in one step -- (function() { .....})();. The code creates a script element, sets its type and source and appends it to the document. We've used lots of dereferencing to save characters, such as assigning d=document. Now, on the server-side, we create a little JavaScript file that contains our familiar alert statement:

alert("Title: " + document.title);

Try out our new example:

Drag the following link to your toolbar or bookmark it:
Title2

OK, so what's the big deal? Didn't we just do the exact same thing in a more complicated way? Yes and no. Yes, the new bookmarklet does exactly what the old bookmarklet did but in a different way. It included a JavaScript file into the context of the current page. Into that file we could have put as much other JavaScript as our hearts desired. We could even, with some precautions, have included our favorite Ajax library to manipulate the DOM and make asynchronous requests. The bookmarklet thus becomes just the leading wedge that allows us to load in more substantial program logic.

For a Web 2.0 example of a bookmarklet, have a look at Blummy, which allows you to share useful bookmarklets with other users. A word of warning, however, about bookmarklets: you're inviting someone else's code into your browser. Once in, they can do a great deal of mischief. When evaluating bookmarklets ask yourself, "how much do I trust this company or individual?"

Next time we'll go beyond the mere "Hello World!" and try to be a little bit more disruptive.

    Technorati : ,

More Javascript Code Generators and Another Ajax OS

So, I missed two Javascript code generators, found the new home of a third, and found one more Ajax OS beastie. First the code generators:

  • ParenScript has a new home. This is the Lisp->Javascript code generator. An example:
    (js
      (defun foobar (a b)
        (return (+ a b)))) 
    

    and the Javascript:

    function foobar(a, b) {
      return a + b;
    }
    
  • ST2JS - A smalltalk to Javascript translator. Not a project overflowing with documentation and friendly explanations.
  • jsc - this is another C# (or ) to Javascript code generator.

    The compiler extracts CIL from a .net assembly. It filters out the classes which are marked with the ScriptAttribute. It selects the target language and emits the source.

    I've already blogged about this tool once before, but it does belong in any listing of Javascript code generators, so in it goes.

Next, on the heels of our entry on Atomic OS, we have another cute little command line shell toy in Ajax: JS/UIX Terminal.


jsuix.jpg

It's cute to be able to play invaders in the browser, for about 5 minutes. Under the covers, it purports to be an OS written in Javascript, implemented on top of the browser:

JS/UIX is an UN*X-like OS for standard web-browsers, written entirely in JavaScript (no plug-ins used). It comprises a virtual machine, shell, virtual file-system, process-management, and brings its own terminal with screen- and keyboard-mapping.

Cute as well, and probably an interesting learning experience. Not sure if the OS on top of the Browser is where the future of Ajax is. Abstracting services down to that level seems like overkill.

Technorati : , , , , ,

AtomicOS - Another AjaxOS

What's bigger than a framework? An Operating System. While many of the Ajax OS's that bill themselves as Operating Systems are nothing more than a pretty desktop metaphor, there is at least one project that aims to build an Ajax OS from the ground up: Atomic OS. It has a ROM and a Kernel and build itself up much like a real operating system on real hardware. The only difference is that everything is written in Javascript. It's interesting what happens when OS design principles are applied to the browser.

It's still under development. If you want an early taste, you can look at it's predecessor, WAJAX. That's already pretty impressive, so I look forward to Atomic OS.

wajax.jpg

Technorati : ,

The Hazards of Exposing Business Logic on the Client, Part II

A double dose of "I told you so" today: as it turns out, stealing an idea is hard work, while stealing an implementation is dead easy. By that I mean that if you want to steal a server-based web application, you either have to hack in to steal the code or do the hard work of reverse engineering and coding a clone. But if you're developing client-side code in JavaScript, you are vulnerable to theft. It's the recurring theme of Ajax and Leaky Business Logic, and I'm going to keep talking about it until it doesn't happen anymore.

You remember the incident where the image editing webapp Snipshot was ripped off by Cellsea? Well it looks like it's happened again, this time with one of Emil Eklund's WebFX tools -- LiteSpellChecker -- being ripped off by SpellingCow. Emil reviews the code and appearance of his original program with the derivative one and finds several suspicious similarities. His program was a demo, but copying code whether demo or not without attribution is a big no no.

If you are going to write business logic on the client side rather than just sticking to display logic, you need to at least obfuscate your code to make maintenance and reverse engineering a headache. Better yet, stick to writing Ajax applications in server-side frameworks like Echo2 and ZK.

Update: Thanks to Doug Clinton for pointing out the update from Emil. I guess all I can add is the only thing that makes this not a ripoff is Emil's laid back attitude.

Technorati : , , ,

A Little Silly - TopJax


If you know Unix/Linux, you know top, the command that lets you see top executing processes, sorted by CPU usage. Now you can get the command on the web, thanks to Ajax, via topjax. As the web page says, you have to be a little lazy to run this one, though.





Technorati : ,

BJAX With Greasemonkey

I've had a number of people write me wanting to know how to do BJAX (Browser Extension and AJAX) with Greasemonkey on Firefox. I thought I'd give a simple little example here. The example will show a small box in the top left corner of a google page. This box will display the weather in Chicago as served up by a Yahoo! RSS feed, refreshed every 30 seconds. Yes, yes, this isn't terribly useful, but that's not the point. Also, this is a quick hack. It won't work on IE or probably most versions of browsers.


www.google.com_search.png


OK, having dispensed with preliminaries, let's get started. First you'll need to install Greasemonkey. Once you've done that, download the example script here. You'll need to load it in a browser window and install it.


There are a couple of differences in programming Javascript in Greasemonkey as opposed to a regular browser environment. We'll only touch on a few of these here, but you should have a look at Dive Into Greasemonkey for a more complete treatment.


OK, the first step in our extension involves looking for a particular method:


if (typeof GM_xmlhttpRequest != 'function') {
return;



As you can probably guess, GM_xmlhttpRequest is a special version of XMLHttpRequest that allows you to access any remote site. It isn't present in all versions of Greasemonkey, so you have to check for it. Next, we check that we have the top window. We don't want the box showing up in IFrames.


if (window == top) {



The next bit looks pretty standard; we create a div, give a few of the elements id's and insert it at the beginning.


var mybox = document.createElement("div");

mybox.innerHTML = '<div id="bjax_box" style="margin: 0 auto 0 auto; ' +
'position:absolute; left:15px; top:15px; width:175px; opacity: .75; filter: alpha(opacity=75); z-index:100; ' +
'margin: 5px; padding: 5px; overflow: hidden; height: auto; ' +
'font-size: 8pt; font-weight: bold; font-family: arial, sans-serif; background-color: #ccffcc; ' +
'color: #000000;"> ' +
'BJAX in Action! <br/> Chicago weather: <br/> ' +
'<p id="bjax_weather"></p>' +
'</div>';


document.body.insertBefore(mybox, document.body.firstChild);



There remains the periodic call to GM_xmlhttpRequest. We parse the RSS XML and grab the second description. It's an example. In an actual app you would want to be a little more careful.


window.setInterval(function() {
GM_xmlhttpRequest({
method: 'GET',
url: 'http://xml.weather.yahoo.com/forecastrss?p=60602',
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'application/atom+xml,application/xml,text/xml',
},
onload: function(responseDetails) {
// convert string to XML object
var xmlobject = (new DOMParser()).parseFromString(responseDetails.responseText, "text/xml");
var condition = xmlobject.getElementsByTagName('description')[1];
var weather = document.getElementById('bjax_weather');
weather.innerHTML = condition.firstChild.nodeValue;
}
});
}, 30 * 1000);



A few quirks you may want to watch out for (see also this pitfalls articles):


  • When you get a DOM element in Greasemonkey, it will be a XPCNativeWrapper. That type doesn't have many properties you've come to expect, such as onclick. You can add event listeners using document.addEventListener('click',... instead.
  • The scope of functions and variables. Greasemonkey wraps your code in an anonymous functions, so you variables and functions are not available to other Javascript in the file. Use anonymous functions where you have to pass a function pointer.

Now that you've been through this little example, you may want to uninstall the example BJAX component. Who, after all, wants weather hanging over their google search?


One additional interesting feature of Greasemonkey is that once you've written your script, you can compile it into a Firefox extension.



Application Watch - Domain Lookup with AJAX

As if you didn't already have enough ways to register domain names, here is a domain lookup tool that uses AJAX to query whois as you type as well as suggest some word completions in a sidebar. That way you can settle on purlo.net on your way to registering purloin.com. Maybe rather than word completion, this thing needs a thesaurus.


dns.jpg

Technorati :

HSE 1.1 - Hibernate, Spring and Echo2

Let a hundred flowers bloom, let one hundred schools of thought contend. -- Chairman Mao

Maybe it's not a good idea to have so many AJAX UI frameworks contending for our attention; it confuses users and has people sitting on the sidelines waiting for things to shake out. The same can not be said of AJAX application frameworks -- frameworks that provide you with the infrastructure to write full featured n-tier applications. In my opinion there aren't enough of those.

I've been watching the development of HSE -- Hibernate, Spring, Echo2 -- and it's already come together into something pretty useful. Right now it's more of a sample application that you can use as a starting point for developing your own application. If you haven't come across these various tools before, let me give you a quick overview of each of them in turn:

  • Hibernate - an Object Relational Mapping tool that allows you to map Java Objects to RDBMS tables. There are a ton of these types of tools, both commercial and open source. Hibernate is so slick and featureful it's pretty much killed the commercial market here.
  • Spring Framework - this is the one framework whose main purpose is to allow you to design better software. From their mission statement: OO design is more important than any implementation technology, such as J2EE. After using it, you'll wonder how you ever developed applications the old way. I strongly urge you to check this one out, even if you decide not to investigate HSE further.
  • Echo2 - Java AJAX component GUI framework that allows you to write web applications the way you do Swing programs.

By combining these tools, the HSE framework already sports some useful features:

  • User and group based authentication and entitlements/permissions.
  • Input validation with AJAX alert dialogs.
  • Sample UI for managing users, groups and permissions.

A short but promising list. I'd like to see it fleshed out a bit with things like a workflow facility, support for messaging and asynchronous processing (see Mule ESB for some ideas), and scripting (Groovy, anyone?). If you're a developer out there thinking of rolling your own AJAX framework, I'd like to encourage you to supress that urge and contribute to a GUI framework like Echo2 or an application framework like HSE. Don't reinvent the wheel when so many new widgets and tools are waiting to be invented.

HSE 1.1 - Hibernate, Spring and Echo2

Let a hundred flowers bloom, let one hundred schools of thought contend. -- Chairman Mao

Maybe it's not a good idea to have so many AJAX UI frameworks contending for our attention; it confuses users and has people sitting on the sidelines waiting for things to shake out. The same can not be said of AJAX application frameworks -- frameworks that provide you with the infrastructure to write full featured n-tier applications. In my opinion there aren't enough of those.

I've been watching the development of HSE -- Hibernate, Spring, Echo2 -- and it's already come together into something pretty useful. Right now it's more of a sample application that you can use as a starting point for developing your own application. If you haven't come across these various tools before, let me give you a quick overview of each of them in turn:

  • Hibernate - an Object Relational Mapping tool that allows you to map Java Objects to RDBMS tables. There are a ton of these types of tools, both commercial and open source. Hibernate is so slick and featureful it's pretty much killed the commercial market here.
  • Spring Framework - this is the one framework whose main purpose is to allow you to design better software. From their mission statement: OO design is more important than any implementation technology, such as J2EE. After using it, you'll wonder how you ever developed applications the old way. I strongly urge you to check this one out, even if you decide not to investigate HSE further.
  • Echo2 - Java AJAX component GUI framework that allows you to write web applications the way you do Swing programs.

By combining these tools, the HSE framework already sports some useful features:

  • User and group based authentication and entitlements/permissions.
  • Input validation with AJAX alert dialogs.
  • Sample UI for managing users, groups and permissions.

A short but promising list. I'd like to see it fleshed out a bit with things like a workflow facility, support for messaging and asynchronous processing (see Mule ESB for some ideas), and scripting (Groovy, anyone?). If you're a developer out there thinking of rolling your own AJAX framework, I'd like to encourage you to supress that urge and contribute to a GUI framework like Echo2 or an application framework like HSE. Don't reinvent the wheel when so many new widgets and tools are waiting to be invented.

Asynchronous Update in Echo2

I've been sitting on my second in a series of Echo2 tutorials a little too long. (What can I say? Busy, busy.) The core of the tutorial is all about asynchronous updates -- updating the browser from the server as if by magic, without a click or a mouseover. There's a bit of a trick to doing this in Echo2 and understanding it depends on understanding how the framework handles asynchronous communication with the browser. (I apologize in advance that this isn't as verbose as a tutorial, but I thought it might be useful to someone in this form nonetheless.)

First you have to understand that this async update from the server isn't actually a server push but rather a client pull. On the client side, if asynchronous updates are turned on in an Echo2 app (more on how they are turned on later), then the browser polls the server (by default every .5 seconds) for updates. During updates, the Client Engine locks the UI, i.e. you can't click, drag or do anything while an update is taking place (so don't make your tasks long running). On the server side, async updates are turned on by creating a task queue. When the Client Engine contacts the server, those tasks in the queue are processed, one by one, and if any modifications are made to the UI model in on the server, those changes are propagated to the client. The reason for the queue is that Echo2 abides by the pre 1.3 J2EE spec that says that you cannot spawn threads that are not handled by the container. Therefore all modifications of UI components have to take place in a servlet thread. (In fact, if you try to modify any UI components from another thread, Echo2 will throw and exception.) The queue simply allows you to line up tasks that then are executed in the appropriate thread.

The act of creating such a queue causes the server to update the client so that the Client Engine periodically polls the server. If you destroy all of the queues, the client stops polling. (Of course a client-server communication has to take place in order for the client to be notified of this.)

But how do you put tasks in the queue? One naive approach would be to spawn a thread that periodically puts a task in the queue. The problem with this approach is that the queue is only cleared when the client polls the server. If you have a thread putting tasks in the queue and the client navigates away from your page, you could have a thread filling up the queue for quite some time. You also have to put lifecycle methods in place to clean up your thread and any associated resources. The cleaner solution is to override the hasQueuedTasks method of the ApplicationInstance class. This method is called every time an async poll comes in from the client.

Here is my simple solution to managing the async push in Echo2. Note that there are a few things missing here, such as clearing or pausing all scheduled tasks, catching exceptions, etc.. You'll have to decide some of those details on your own. Note that I've used a thread-safe set with a thread-safe iterator -- very handy:

package ajaxsample.app.echo2;

import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import nextapp.echo2.app.ApplicationInstance;
import nextapp.echo2.app.TaskQueueHandle;
import nextapp.echo2.app.Window;
import nextapp.echo2.webcontainer.ContainerContext;

public class AjaxSampleApplication extends ApplicationInstance {

    private Window mainWindow;
    private TaskQueueHandle tqh;
    private final static int ASYNC_PERIOD = 5000; // 5 seconds
    private Set<UpdateTask> tasks;
   
    @Override
    public Window init() {
        tasks = new CopyOnWriteArraySet<UpdateTask>();
        tqh = createTaskQueue();
        // have the client poll every 5 seconds
        setUpdateInterval(tqh, ASYNC_PERIOD);
        mainWindow = new Window();
        mainWindow.setContent(new DefaultForm());
        mainWindow.setTitle("Ajax Sample");
        return mainWindow;
    }

    /**
     * Set the polling interval from the client for the task queue.
     *
     * @param tqh The task queue to modify
     * @param interval polling interval in milliseconds for client engine
     */
    private void setUpdateInterval(TaskQueueHandle tqh, int interval) {
        ContainerContext containerContext = (ContainerContext) getContextProperty(ContainerContext.CONTEXT_PROPERTY_NAME);
        containerContext.setTaskQueueCallbackInterval(tqh, (int) interval);
    }
   
    /**
     * Add an UpdateTask to the default taskQueue schedule
     * @param r
     */
    public void schedulePeriodic(UpdateTask r) {
        tasks.add(r);
    }

    /**
     * Remove a task from the default task schedule.
     *
     * @param r
     * @return was the task present in the default task schedule
     */
    public boolean unschedulePeriodic(UpdateTask r) {
        return tasks.remove(r);
    }
   
    /**
     * Insert tasks from out default schedule into the default queue.
     *
     * @return do we have queued tasks?
     * @see nextapp.echo2.app.ApplicationInstance#hasQueuedTasks()
     */
    @Override
    public boolean hasQueuedTasks() {

        Iterator<UpdateTask> it = (Iterator<UpdateTask>) tasks.iterator();
        while (it.hasNext()) {
            UpdateTask task = it.next();
            if (task.ready()) {
                enqueueTask(tqh, task);
            }
        }

        return super.hasQueuedTasks();
    }
   
   
    /**
     * Best practice. Returns the current application instance cast to the
     * correct type.
     *
     * @return the active <code>AjaxSampleApplication</code>
     */
    public static AjaxSampleApplication getApp() {
        return (AjaxSampleApplication) getActive();
    }

}

How would you make use of this queueing mechanism? Here's an example that updates a label every 5 seconds:

package ajaxsample.app.echo2;

public interface UpdateTask extends Runnable {
    boolean ready();
}

[...]

private static final long UPDATE_INTERVAL = 5000;
private Label countLabel = new Label();
private int count = 0;

[...]

// create an update task for the counter
UpdateTask task = new UpdateTask() {
    private long lastRun = 0; // in forever
    public boolean ready() {
        // more time has passed than our interval
        return UPDATE_INTERVAL <= (System.currentTimeMillis() - lastRun);
    }

    public void run() {
        // update the runtime
        lastRun = System.currentTimeMillis();
        count++;
        countLabel.setText("Counter = " + count);
    }
};

// now schedule it
AjaxSampleApplication.getApp().schedulePeriodic(task);

That's quite a bit of code that doesn't really fit the component GUI model. This is one area where I think ZK gets it right where Echo2 gets it wrong: the whole async update business should be abstracted into a timer component (see the timer in the ZK demo). If someone needs a special async update processing that cannot be accomodated through a timer, they can always hack the hasQueuedTasks method.

   

Widget Watch - Echo2 Widget Panel

Well it's happened. Down in the ferment that is the Echo2 Developer Forums, developers are contributing reusable components to the Echo2 framework. Beyond the EchopointNG components, lots of other developers have been throwing their hats in the ring. One fellow took a look at the new google home page and thought that a draggable, animated component panel like that would be a good thing for Echo2. He announced his component panel on the Echo2 development forum. Here's a screenshot of a demo in action:

echo2comp.JPG

I've put up the demo for those who want to test it out for themselves. (It's not my demo, i.e. I didn't write it, I'm just putting it up.)

A few words about the demo. To use it, click the "Add Widget" text at the top to add widgets, then drag them around. Use the other buttons to change the behaviour of the panel. OK, have at it.


Another GWT Tutorial

Update: I've posted 36 GWT Tutorials, a more up-to-date list of GWT tutorials.

I know I promised this would be ZK week, but my code reading is going a little slower than I expected. So let me work in some more news about GWT. I know, I know, you're sick of GWT (or maybe you're not). But there's a nice new tutorial over at java.net. It's called Kickstarting Google Web Toolkit on the Client Side and it provides, in increasing order of sophistication, three example GWT applications: a simple "Hello World!" app; an amusing Zork type adventure game ("unlock door", "go north", "read plaque", etc.); a cool little animation made up of a few simple yet effective pieces.

anim.jpg

This is probably the best GWT tutorial I've see to date as it actually tries to do something beyond flinging around some labels and text fields. Of course, the tech publishers are probably hard at work on a book that builds a non-trivial application with persistence and rich features. This will have to tide you over until then.

 

The Hazards of Exposing Business Logic on the Client

Via Ajaxian we get an object lesson in the dangers of exposing business logic in the browser:

Beau Hartshorne of Snipshot (formerly Pixoh) says "massive chunks" of Cellsea code are identical to Snipshot. "This is not an accidental inspiration. Check out the cropping code, the resizing code, and so on. We've also noticed that portions of their website are also stolen directly from ours ... We are contributors to MochiKit open source project. However, the code in question is proprietary and was taken directly from out site."

Can I say "I told you so?" I've blogged about the danger of Ajax and Leaky Business Logic before. What is the danger here and the lesson the be learned?

  • Don't put your crown jewels in the browser. See if you can't lock a fair bit of your business logic on the server side by using a server-side component framework like Echo2 or ZK.
  • If you're going to deploy meaningful applications in Javascript, do what people have been doing with script source code for decades: obfuscate. You can do something simple like renaming all of your variable to one or two character names, or you can use a code generation framework like GWT or Morfik that produce unreadable code from the beginning. Be forewarned that code generators can be vulnerable to decompilers -- in short, if someone knows how GWT generates it's code, you could possibly reverse the process and produce the original source code.
  • Build in anti-theft mechanisms. This could be something as simple as a method that checks to see that the url the application is running on is the correct one, otherwise display a nasty message. You could make this as tricky and complicated as you like, all the way to encrypting big chunks of code with the website url and only decrypting them at runtime.
  • Hold out for "byte compiled" Javascript.

A combination of all of these may be what we end up with. I'm not sure I'd want to run any script in my browser, though, that I can't understand. Still, you would hate to be the victim of code-theft as has apparently happened to Snipshot.

How similar are these two programs? Well, Cellsea offers a bunch more functions, but they do look very similar, both in terms of the UI and the underlying code. The original Snipshot is here and the knock off here. You be the judge.

If you are really hungry for a good AJAX image editing app, the best of the bunch of them may be Phixr, which gives you preview, the ability to marquee select for certain operations, etc. Slick, even if the UI is a bit jumpy.

phixr.jpg



Product Watch - Nusearch.com and Zohoshow

 

Two new AJAX flavored products launched today: Nusearch.com, a search engine with AJAX whizbang, and Zohoshow, the last piece in the Zoho Office Suite, a replacement for MS Office that includes Zohowriter.

As of this writing, it looks that Nusearch, with all it's AJAX innovations, has succumbed to the first day onslaught. I'll try and update this post when I manage to get through.

As for Zohoshow, it's basic, allows you to import existing Powerpoint files. Don't expect to do any charts or graphs or animations, though.

zohoshow.jpg

I've said before that presentations are just about the last thing for which I would want to depend on network connectivity. How many conference rooms have you been in that didn't give you access to the outside world?

Update 1: Nusearch came back up. Yes, there's some AJAX there, but in my opinion it's rather annoying. The search engine will let you preview their cached version of a page just by mousing over it's entry. It's so twitchy, though, because the table rows are close together. Also, the preview is really no better than a frame or iframe. Snooze. From a pure search perspective, it doesn't seem to do a very good job of sifting and ranking. The search results have a somewhat spammy feel to them.

nusearch.jpg

 

I like dzone's little popup screenshot much better.

dzone.jpg

Ajax Forms - Enhancing the user experience

The web is filling up quickly with examples of Ajax powered sites that allow us to do things we’ve never been able to do before on the web. From note taking apps, to spreadsheets, photo editors, and online games, Ajax apps like these are continually pushing the boundaries of what is possible, and in the process changing the way we work live and play on the internet.

However, we can also use Ajax to build better user experiences for the tasks we’ve already been performing on the web.  One kind of task crying out for Ajax attention is form submittal, in which a user fills in a set of fields and presses the submit button. 

Almost all forms today use the POST action in the SUBMIT button to upload data to the server, where proc