Pete

Pete

(10 comments, 271 posts)

This user hasn't shared any profile information

Home page: http://petelepage.com

Posts by Pete
JavaScript code on computer screen

HTML5 Hack-A-Thon Coming To A City Near You

1

JavaScript code on computer screenWell, hopefully it’ll be near you – if not, let me know in the comments where you are so we can try to get some more of these events set up!

Google is holding a few developer focused hack-a-thons around the US and would like to invite you to attend. At these events, we will be covering some of the latest and greatest features of HTML5, Chrome Web Store and In-App Payments. You will learn about the end to end flow of building a web app, distributing the app and monetizing it using these APIs. You will also have the opportunity to work hands on with the APIs and ask our experts (including me) questions. I’ll be helping out in Chicago and Mountain View.

For more information on the events and to register, please check out the location specific links below:

New York – 8/1 – http://www.eventbrite.com/event/1892631913
Chicago – 8/3 – http://www.eventbrite.com/event/1910102167
Seattle – 8/8 – http://www.eventbrite.com/event/1910138275
Mountain View – 8/11 – http://www.eventbrite.com/event/1910202467


* Image http://www.flickr.com/photos/dmitry-baranovskiy/2378867408/

HTML5_Logo_512.png

Showing & Hiding Panels with HTML and CSS

2

I’ve always loved web apps that use little panels that animate in from the sides as a way to show and hide content, settings, or other components of a web page. We used them a couple of times in Tweeter Fall, so I figured I’d share my way of doing them. I wanted to try doing this without any libraries to start, using only HTML5, CSS3 and as little JavaScript as possible, which will work for most browsers, but not all. Once we get it working with the latest stuff, I’ll go back and make the necessary modifications to get it to work across all browsers.

I’m using a slightly modified version of Eric Meyer’s CSS reset to ensure that everything is ready to go, you can use that or other ones as you see fit.

Let’s get started!

First, let’s create the panel where everything will live

<div class="left-panel">
</div>

and we need to apply a bit of CSS. Typically when I start working on something like this, I’ll use super ugly colors to make sure that the stuff that I’m working on sticks out, so in this case, I’m going for a nice bright red.

#left-panel {
  width: 300px;
  height: 400px;
  border: 3px solid red;
  background-color: #fcc;
}

Positioning The Panel

Great, we’ve not got our panel, though it’s not in the right place, but at least it’s on screen. Next, let’s move it to it’s default position, so that it’s minimized. To do that, I’m going to set the position to fixed – I want it so that it’s always on screen. Then, we need to move the left side of the panel into the negative space, and move the panel down the screen.

#left-panel {
  width: 300px;
  height: 400px;
  border: 5px solid red;
  background-color: #fcc;
  position: fixed;
  top: 150px;
  left: -275px;
}

Making the panel appear

To get the panel to be fully visible, we’re going to add both a hover pseudo-class as well as a show class. The pseudo-class will move it out just a bit, to add some realism and a clear indication that the panel has more to show.

#left-panel:hover {
  left: -250px;
}

#left-panel.show {
  left: 0px;
}

Adding controls to show & hide the panel

You could simply show the panel on any hover, but that always gets a little annoying to me, especially when I’m moving my mouse around quite a bit, so I’d rather not do that. Now we need to add the logic that will show and hide the panel. I’m going to use a hyperlink as the main item, and a little JavaScript to toggle the show class. The &gt; will come in handy a bit later. :)

<div id="left-panel">
  <a href="#" onclick="showLeftPanel();" class="controller">&gt;</a>
</div>

The CSS for the hyperlink is pretty simple, it absolutely positions the hyperlink in the upper right hand corner, and removes the underline from the text.

#left-panel .controller {
  position: absolute;
  right: 0px;
  top: 0px;
  text-decoration: none;
}

Hooking everything up

Finally, we need the JavaScript to toggle the CSS class. I’m using a new property off element called callList that gives me similar functionality to a lot of libraries for modifying classes on elements. classList provides the ability to add, remove or toggle classes on elements.

<script type="text/javascript">
  function showLeftPanel() {
    var elem = document.getElementById("left-panel");
    elem.classList.toggle("show");
  }
</script>

Now, when we click on the >, the panel becomes visible, and clicking on it again, makes it disappear, perfect! The panel isn’t exactly beautiful yet, and it doesn’t take advantage of any of the cool CSS3 stuff yet, so let’s add a bit of that.

Adding a bit of style

First, we’ll add some rounded corners to the top right, and bottom right, and a little bit of spacing inside the panel with a 5px padding along all the edges. Next, I’ll add the transtion properties. The first, -wekit-transition specifies that all properties that change (beyond what’s indicated in #left-panel), they’ll appear over 0.5 seconds, and will use the ease-in-out transition. In a bit, we’ll need to add the transitions for other browsers that support it – but we’re going to get it working in Chrome first.

#left-panel {
  width: 300px;
  height: 400px;
  border: 5px solid red;
  background-color: #fcc;
  position: fixed;
  top: 150px;
  left: -275px;
  border-radius: 0 1em 1em 0;
  padding: 5px;
  -webkit-transition: all 0.5s ease-in-out;
}

I also need to make a few other modifications to a couple of the other classes. I’ve changed the left on #left-panel.show to -5px. That hides the border on the left, and ensures the 5px padding on the left doesn’t look too odd. I could have modified the border to only display on three sides, but it kind of felt like more work to me. ;)

#left-panel.show {
  left: -5px;
}

Add hinting to help the user

The other thing that I want to do is make a few changes to the open/close hyperlink. Because of the rounded corners, we need to move it in a bit, but I’m also going to add transitions to it as well.

#left-panel a.controller {
  position: absolute;
  right: 5px;
  top: 5px;
  text-decoration: none;
  -webkit-transition: all 0.5s ease-in-out;
}

So why add the transitions? When the panel is closed, we’re using a > which renders like an arrow pointing to the right, to indicate the panel can be closed, we want the arrow to point to the left, so I used a transform and rotated the character by 180 degrees, and suddenly my > is a <!

#left-panel.show a.controller {
  -webkit-transform: rotate(180deg);
}

Our first working version

Alright, so here’s the final code that works in Chrome, with some nicer colors:

The HTML

<div id="left-panel">
  <a href="#" onclick="showLeftPanel();" class="controller">&gt;</a>
</div>

The CSS

#left-panel {
  width: 300px;
  height: 400px;
  border: 5px solid #555;
  background-color: #ccc;
  position: fixed;
  top: 150px;
  left: -275px;
  border-radius: 0 1em 1em 0;
  padding: 5px;
  -webkit-transition: all 0.5s ease-in-out;
}

#left-panel:hover {
  left: -250px;
}

#left-panel.show {
  left: -5px;
}

#left-panel a.controller {
  position: absolute;
  right: 5px;
  top: 5px;
  text-decoration: none;
  -webkit-transition: all 0.5s ease-in-out;
  color: black;
  font-weight: bold;
}

#left-panel.show a.controller {
  -webkit-transform: rotate(180deg);
}

And finally, the JavaScript

<script type="text/javascript">
  function showLeftPanel() {
    var elem = document.getElementById("left-panel");
    elem.classList.toggle("show");
  }
</script>

But what about other browsers?

To get this working in other browsers, we need to change our CSS a bit to add other vendor prefixed items, and we’ll need to make some changes to our JavaScript as well.

Safari

Safari doesn’t support classList’s yet, so we need to modify our JavaScript here. The absolute easiest way to make this change would be to use jQuery’s toggle function, but I want to do this without any libraries. That means we’ll have to do some feature detection to see if elem.classList is supported, if it is, we’ll use that, otherwise we’ll manually add or remove the show class.

<script type="text/javascript">
  function showLeftPanel() {
    var elem = document.getElementById("left-panel");
    if (elem.classList) {
      elem.classList.toggle("show");
    } else {
      var classes = elem.className;
      if (classes.indexOf("show") >= 0) {
        elem.className = classes.replace("show", "");
      } else {
        elem.className = classes + " show";
      }
      console.log(elem.className);
    }
  }
</script>

That’s all we need for Safari to work!

Firefox and Opera

Firefox 3.6+ and Opera 11.5+ both support classList, and previous versions will fall back to the manual method, so our JavaScript is good to go. But, the -webkit- vendor prefixed stuff needs a little love and thankfully it’s pretty easy!

In #left-panel and #left-panel a.controller add:

-moz-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;

In #left-panel.show a.controller add:

-moz-transform: rotate(180deg);
-o-transform: rotate(180deg);

Internet Explorer

Unfortunately, Internet Explorer (9 or the Platform Previews for 10), don’t have support for transtions yet, which mean that our panels just appear and disappear, but that’s not an awful experience, it’s just not ideal. In fact, the experience for Internet Explorer 7, 8 and 9 is identical except IE9 does have rounded corners. Just in case they add support for transitions in the future, I added the -ms- vendor prefix already.

Summary

There you go – you’ve not got a simple panel that can be displayed by the simple click of a link, and gets out of the way when not needed. It works in IE7/8/9, Chrome, Firefox, Opera and Safari and I suspect it will work in IE6, though I didn’t test that.

Give it a try at http://petelepage.com/scratch/slider-panel/

greenhouses

Is It Time To Rethink Web Navigation?

0

While on my way into work this morning, I read a post on SixRevisions asking the question “Is It Time To Rethink Website Navigation?” For a very long time, navigation on websites has been stagnant, it’s either a navbar across the top, or maybe down the side. Sometimes, with a little JavaScript, it’s interactive, but it almost always contains the same types of link. The logo almost always takes you “home”, there’s an about link, a site index link, contact us, well, you know what I’m talking about. Oh, and don’t forget about the standard footer at the bottom of most sites.

We’ve certainly seen a number of web sites start to push the boundaries of traditional navigation and they call out a couple like The Wishes Greenhouse at Clair et Net or how other sites use responsive web design to provide a better experience depending on the capabilities of the device you’re on.

Web Pages & Sites vs. Web Applications

This worked well when the web was only about sites and pages – navigating from one page to another and consuming content. But as we see more and more web applications come online, the traditional navigation model doesn’t work any more.

I think the author missed a great opportunity though to talk about the difference in navigation between web applications and web sites – two very different models. In a web site, navigation provides a connection from one page to another and a way to move around from one piece of content to another. Web application navigation is different, instead of moving between pages, it’s more about providing the user with an ability to control and interact with content. Changing the paradigm away from navigation towards control is one of the core components that separate websites and pages from applications.

Let’s take a quick look at Music by Google. Notice there isn’t a nav bar across the top, or on the sides, and there isn’t a footer either? Instead along the right side, there are a number of links that change my view. At the bottom, where the footer normally would be are the player controls (back, play, forward, volume, etc). Instead of providing links to help me get somewhere – the links on the page help me accomplish something, or change the view that I have (maybe to a different playlist, artist or genre).

Being More App-y

So what makes a web application app-y? Certainly the navigation and controls do. When I look at a web application and how the designers and developers have laid out the navigation, I ask myself how this app might be different if it were a client or mobile application. When was the last time you saw the privacy policy, terms of service or copyright notice not in an about screen on a desktop app, or tucked away under settings in a mobile application? Imagine if that were at the bottom of iTunes and took up the bottom 10%! And we see this all the time in web applications. In fact, GMail is one of my favorite offenders here. Why not tuck that away under settings in top right?

Step Out Of The Box

It will take some time for this paradigm to change, but it’s an important one. Today we still think in the web site and web page “box” too often when creating web applications. Let’s get out of that box, and make web applications feel more like applications and less like web pages.

Chrome Web Store - Shopping Bag

What Makes For A Great Web App?

0

What makes a web application great?  I recently sat down with Christos, one of the guys on my team to look at a number of the top web applications in the Chrome Web Store to try to identify which ones were really great, versus good, and what advice we could give to the good apps to become “great”.

Before we could start rating these apps, we built out a set of principles and criteria that we felt were important in providing a great application experience on the web.  We based our principles on some earlier work done by Mike and Paul, and refined their thinking into three principles.  We tried to create a set of objective criteria for each of the principles that we could use to rate the apps – and while we didn’t actually assign a score, we wanted to be as objective as possible.

A Tight Focus

A web application has a tight focus encouraging people to interact, engage, and accomplish something, rather than passively view content. It doesn’t distract people with content or components that are orthogonal to the task they’re trying to complete.  People integrate it into their day to day lives because it feels like a natural extension of the things that they understand and do every day.

  • The application is limited to a single, core scenario
  • Orthogonal scenarios and tasks are removed from view and not presented to the user
  • The primary application components are accessible at all times
  • Standard web page content and navigation is minimized and the application controls are the primary focus
  • The application looks and behaves consistently across different screens, dialogs, controls and other components
  • The application starts immediately and requires no set up or configuration before it’s first use
  • When starting the application, the user is taken directly to the application instead of a landing page or marketing page
  • The application can be used without registering or signing in, or the sign in/up process is extremely easy

Rich Visual Experiences

A web application provides rich visual experiences that will delight the eye without distracting the mind.  A positive first impression makes users comfortable, assures them your application is reliable and professional and encourages people to make the product their own.  A great web application puts a premium on aesthetics without sacrificing usability.

  • Appropriate fonts and other typographic features are used to enhance readability
  • Graphics and illustrations are high quality and look professional
  • The application uses all of the screen real estate available to it
  • Textures, gradients, and shadows add to the visual appeal of the application
  • Controls and graphics convey meaning without requiring additional context
  • Controls and graphics offer a manner of realism
  • Standard web page content and navigation is minimized
  • Animations are used to introduce new content, dialogs, or other items that require attention or interaction from the user
  • Window resize events appropriately handle new screen sizes, resized graphics and images
  • Messages and information provided to the user is helpful, easy to understand and actionable

Rich Interactive Experiences

A web application provides a rich, interactive experience that makes technology transparent so people can complete their task confidently without ever having to know or understand what makes the application work.

  • The application feels fast and responsive
  • The application provides appropriate notifications and information to keep the user informed
  • The application follows best practices for building fast web applications
  • The application provides a full featured offline experience
  • Input from the user is validated before being sent to the server and appropriate input types are used
  • Adding or removing data from the application is easy

A couple of my favorite apps

QuickNote

QuickNote was on application that stood out in this category – not only does it focus on it’s primary task (note taking), it didn’t require any setup or logging in to get started.

Flixster

I’m a web developer who knows enough about design to appreciate good design, but not enough to do it myself.  Flixster was a good example of involving design early on in the process – the use of rich CSS3 features like gradients, shadows and such make the app visually appealing and fun to use.

280 Slides

I love it when I see a web application and think – it must be Flash, only to find out that it isn’t – seeing the creativity and ingenuity of other web developers is awesome.  280 Slides is one of those web applications.  Like PowerPoint or Keynote, it’s an app to build slide decks and presentations – but it’s all built using the open web stack.  It was built using Cappuccino, a really powerful web framework for building apps, not web sites.  Def worth checking out.

HTML5_Logo_512.png

GoDaddy and AppCache Manifest Files

1

In trying to add HTML5 Application Cache support to one of my web apps today, I hit a few little snags with my hoster (GoDaddy with a Shared Deluxe Windows account) and wanted to share as I’m sure other people will run into the same thing.

Each time I uploaded my web.config file, I kept getting 500 server errors that weren’t very helpful.  As it turns out, the extension .manifest is already taken by the mime-type application/x-ms-manifest, and when I tried to override that, IIS got kind of angry, and served the 500 Server error.  I wasn’t quite sure what was happening, but was able to figure it out by reverting to my original web.config file, and requesting the appcache.manifest file that I had already uploaded.  Sure enough, using the network tab in the Chrome DevTools, I saw it was being served back with the wrong mime type.

To resolve the issue, I added a new static file handler for .appcache files in the system.web -> httpHandlers section.  If you don’t do this, IIS doesn’t know about the file type and it won’t serve unknown file types at all.  Then in system.webServer -> staticContent, I added a mimeMap extension for .appcache files with the mimetype of text/cache-manifest.  After uploading the web.config file again, I retried my request, and sure enough, everything worked perfectly!

My final web.config now looks like…

<configuration>
  <system.web>
    ...
    <httpHandlers>
      ...
      <add verb="GET,HEAD" path="*.appcache"
        type="System.Web.StaticFileHandler" />
    </httpHandlers>
  </system.web>
  ...
  <system.webServer>
  ...
    <staticContent>
    <mimeMap fileExtension=".appcache"
      mimeType="text/cache-manifest" />
    ...
    </staticContent>
    ...
  </system.webServer>
  ...
</config>

Check out this tutorial on Application Cache at HTML5Rocks.com. Also, you can find a full list of the default mime types provided by GoDaddy’s IIS servers here.

[Update 6/30/11 @ 1:53pm] @Paul_Irish pointed out that the recommended extension is .appcache specifically to avoid the unregistered Microsoft extension, and referred to a bug on HTML5.org. So there you have it! :)

Chrome Web Store - Shopping Bag

The Anatomy of a Great Chrome Web Store Listing

2

Your first chance to make a great impression with a new user is often on your application listing page in the Chrome Web Store. People will make a split second decision whether to install your application based on what you put on there, so it’s important to make a great first impression. Let’s take a look at what makes a great Chrome Web Store application listing. This guide highlights a couple key components of a great Chrome Web Store listing. I tried not to repeat content from the documentation, but instead tease out the important parts or best practices. Be sure to follow the links for additional resources or details.

TweetDeck & Google Maps



I think both TweetDeck and Google Maps do a great job of providing a compelling, and interesting listing, so we’ll use those as our primary examples.

Category

Putting your application in to the most appropriate category will make it easy for users to find your application when they browse the store. You can choose up to two categories that are most appropriate for your application. You can find a list of the different categories as well as a description and examples for each in the Chrome Web Store developer documentation.

Even though you can choose up to two categories, and your application will be listed under both, it will only show one category on the navigation breadcrumb when you view it in the Chrome Web Store. Unfortunately at this time there is no way to change which one is listed when you link directly to the page.

Header Details

Screen Shots and Video

Screen shots can be one of the most compelling factors in a user’s decision to install or buy an application, so it’s important to provide at least four or five screen shots that give a user a sense for how your application works, some of the features it offers and an idea of the different elements. You should always start with a beautiful screen shot that provides a detailed overview of the application experience first, and then drill into the additional elements. Make sure the screen shots show your application in use, so that users can see how the application works, and how they might use it. If you’re displaying any kind of data from the user, be sure to use safe or sample data in the screen shots instead of blurring things out or accidentally sharing personally identifiable information.

Screen shots should be full bleed images with square corners that are 400×275 pixels. Very few applications will actually fit within those dimensions, which means you may have to do some creative scaling, or cropping to provide appropriate screenshots. Be sure to not over-compress or scale images so that you can’t see any of the detail. Further details about supplying screen shots are available in the Chrome Web Store documentation under Supplying Images.

A picture may be worth 1000 words, but video is worth many more. The Chrome Web Store allows you to add a YouTube video to the screen shot collection, allowing you to provide a richer way to show people your application, and convince them to install or buy it. Keep in mind that in many cases, people haven’t yet made the decision to install or buy your application, and likely won’t be willing to invest a lot of time, so optimize for a short, high quality overview that highlights the main features and will encourage people to try it.

Icon

Your application’s icon represents identity of your application, and is an important part of the overall brand. The icon should be professional, and appropriately sized so that it’s not pixelated or skewed. The icon file should be a 128×128 pixel PNG, where the actual icon size should be 96×96 (for square icons); an additional 16 pixels per side should be transparent padding, adding up to 128×128 total image size. Additional details about icons can be found in the Supplying Images section of the Chrome Web Store documentation.

Verified Domain

Verifying your domain via the Google Webmaster Tools is like adding a certificate of authenticity to something that you’re going to buy in the store. A verified application tells potential users they’re about the install a genuine, user experience from your site – and that they’re not getting a cheap, or potentially unsafe knock-off. Also, be sure the domain name that you’ve verified and are using makes sense, and isn’t a development or staging domain; which may scare away your users.

Short Description

The application manifest file (manifest.json) has a property for a short description of your application. Use this to tell users about what your application does and why they should get excited and care about it. It’s limited to 132 characters, and cannot include any HTML. For example, the description for Angry Birds is simply “Birds! Slingshots! Destruction! Feathers! Fun!” For Gmail, it’s “Fast, searchable email with less spam.”

Customized Header Background

You can supply a customized background for the header description that appears on the right side of the header in your application’s store listing. The header background allows you to enhance the identity and branding elements on your listing page. When supplying the background image, make sure your app’s title and description are still readable and that the background elements don’t distract from the overall listing.

The header background image should fill the entire 570×275 pixel canvas, though don’t put anything important in the bottom 60px as those are reserved for the rating, buy or install buttons. Be sure to choose a background color that will provide the appropriate contrast with either white, or black text, though a dark or medium background color is recommended, like in this example. Additional details can be found in the Header background section of the Chrome Web Store documentation.

Full Description

Beyond the concise description set in the manifest file, a detailed description can be provided via the Chrome Web Store Developer Dashboard. This is your space to really excite your potential users about your application and convince them to install or buy it. If you’ve already built a landing page on your web site, you can likely leverage what you’ve already written here.

You should provide a detailed description of your application, including it’s features, quotes from great reviews, information about recent updates, and any other information that might be relevant to potential users. If your application has a freemium or free trial, be sure to tell users the differences between the paid and free experience so they’re not surprised or disappointed by functionality that they might not have access to.

Remember, this description will be searchable, so be sure to use any key words in your description that might help users to find your application if they try searching for it without knowing the name of it.

If your product is compatible with a Google product, make reference to that Google product by using the text “for”, “for use with”, or “compatible with”, and be sure to include the ™ symbol with the Google trademark. Example: “for Google Chrome™”. For other third party products, be sure to check any requirements that they may have when describing your application.

Other Helpful Components

Version Number & Last Updated

One of the great features of web applications is the ease at which we can add new features, fix bugs and enhance the overall user experience. It’s strongly recommended that you increment the version number in your manifest file and re-upload it to the Chrome Web Store any time you provide significant updates or bug fixes to your application. This ensures that the version number and last updated field on your application listing stay up to date, and users know that you’re application is fresh, and that you’re constantly working to make it better.

Also, when choosing a version number, it’s a good idea to start at 1.0, or as close to it as you can so that people know your application is ready for real world use and that you’re not something that’s still in beta or may not work as expected. If you’re not ready to be out of beta yet, that’s okay, but provide a realistic version number that indicates how close you are to being out of beta. And be sure to stay away from version numbers like 0.0.0.1.

Promotional Images

It’s always a good idea to provide a small and large promotional images; in case your application is chosen to be featured in one of the many featured application listings. If it doesn’t have at least one promotional image, it there’s little chance of it being chosen as a feature application! Both images should use the same branding and identity as the rest of the images that you supplied, and have a dark or medium background with light text. The small image should be 210×140 pixels and the large 585×220 pixels, both with square corners and no padding. Additional details on promotional images can be found in the Chrome Web Store documentation.

Using the Chrome Web Store badge

On your application home page, you can let others know that your app is available in the Chrome Web Store by using the “Available in the Chrome Web Store” badge on your site and even going so far as to do browser sniffing to provide Chrome users with additional messaging. Be sure to check out

Conclusion

There’s a lot you can do to make sure that you make a great first impression with your Chrome Web Store listing that encourages users to buy or install your application. Good luck, and let’s go build some cool web apps!

[Update] – thanks to @mikewest for pointing out a few grammatical and other mistakes!
[Update2]@sethladd reminded me that he’s got a great blog post titled 13 Tips for a Great Chrome Web Store Listing Page

HTML5_Performance_512

TweeterFall – Web Workers

1

How often have you seen this dialog, or something similar – telling you that some scripts on a page are taking too long while your browser has become completely unresponsive. Because JavaScript runs in the same thread as the rest of the browser UI, we’re often faced with the challenge of being unable to run any complex or long running JavaScript without the fear of blocking the browser. That’s where web workers come in.

Web Workers are part of the HTML5 specification and allow you to run scripts in the background, independently of the main browser thread. This means that you can do complex calculations or run scripts that may take a while to run without yielding to keep the page responsive.  The W3C spec has some great examples of use cases and other helpful descriptions that are worth reading for deeper details.  It also notes that workers are relatively heavy weight and are not intended to be used in large numbers.

In order to to maintain thread safety, workers run in an effective sandbox, which means they don’t have access to the DOM or many other components.  To get information back and forth between the worker and the main application, we need to use the postMessage method and listen for message events.

In TweeterFall, we used a worker thread poll Twitter for new tweets and then we ‘pushed’ those new tweets to the main thread.  Let’s have a look how we used workers.

Starting & Stopping the Worker

We only ever have one working running in our application, and to maintain an easy handle to it, we defined it’s variable in the global scope.  We then had two methods that would handle how the worker would behave – startWorker() and stopWorker(). The startWorker() method takes a parameter that provides information about the username or list that we want to pull tweets from, how often we should poll Twitter and the ID of the last tweet we saw.

var myWorker;

function startWorker(settings) {
  settings.cmd = "start";
  settings.lastTweetID = lastTweetID();
  console.log("WebWorker: Starting", settings);
  myWorker = new Worker("scripts/worker.js");
  myWorker.addEventListener("message", newTweetHandler, false);
  myWorker.postMessage(settings);
}

function stopWorker() {
  if (myWorker != undefined) {
    console.log("WebWorker: Terminating");
    myWorker.terminate();
    myWorker = null;
  }
}

In our startWorker() thread, we create the new worker with myWorker = new Worker("scripts/worker.js");, and then add an event listener and listen for any messages that the worker wants to pass back to us – this is the only way we’re going to be able to communicate to the worker because it’s working off in it’s own little isolated world. At this point, the worker exists, and if it wants to tell us anything, we’re ready to listen, but now we need to tell it to do something, which is the myWorker.postMessage(settings);.

Stopping our worker is pretty similar, we check to make sure that we have a valid object, and as long as we do, .terminate() will immediately close the worker without giving it an opportunity to shut down properly or clean up after itself. This works in our case because we don’t have anything in memory and we’re not doing any calculations of any kind. If you may need to save state or want to clean up after yourself, the better way to shut down would be to send a stop message via .postMessage() and within your worker thread, shut down gracefully by calling self.close(); after completing any clean up.

The Worker Thread

Inside our worker thread, we need to set up an event listener to listen for messages from our parent thread and any other code that we want to execute.

self.addEventListener('message', function(e) {
	var data = e.data;
	switch (data.cmd) {
		case 'start':
		  self.postMessage("Worker: Starting");
			setConfig(data);
			readTweets();
			break;
		case 'stop':
		  self.postMessage("Worker: Stopping");
			self.close();
			break;
		default:
		  self.postMessage("Worker: Error - Unknown Command");
	};
}, false);

Our event listener listens for messages from the parent and will start or stop the worker as necessary. When we get the start command, we parse the settings data (setConfig), and then start reading tweets (readTweets()). For sake of readability, I’ll skip the code we used for setConfig(), but it’s easy enough to find if you want it.

function getURL() {
  var sinceID = "";
  if (parseInt(lastKnownTweetID, 10) > 0) {
    sinceID = "&since_id=" + lastKnownTweetID;
  }
  if (typeof userList === 'undefined') {
    return 'http://twitter.com/statuses/user_timeline/' + twitterUser
      + '.json?count=' + tweetCount+ '&callback=processTweets' + sinceID;
  } else {
    //For a list
    return 'http://api.twitter.com/1/' + twitterUser + '/lists/' +
      userList + '/statuses.json?callback=processTweets' + sinceID;
  }
}

function readTweets() {
  try {
    var url = getURL();
    self.postMessage("Worker: Attempting To Read Tweets From - " + url);
    importScripts(url);
  }
  catch (e) {
    self.postMessage("Worker: Error - " + e.message);
    setTimeout(readTweets, 120000);
  }
}

readTweets() is the function that does the dirty work, making a JSONP call to Twitter that requests the latest tweets. We encapsulated the URL generation into it’s own method so that we could use it even if we weren’t using workers. Because we don’t have access to the DOM, we can’t just insert a <script> block, so after getting the URL, we call importScripts(url);, which makes an synchronous call and injects the result into the worker. If we run into any problems, like over capacity, not being able to reach Twitter or anything else, it’s caught in the catch block, and we wait two minutes before trying again. Here’s the JSONP call we make http://api.twitter.com/1/petele/lists/chromedevrel-11/statuses.json?callBack=processTweets.

The request we sent to Twitter includes ?callback=processTweets in the query string which will cause processTweets() to be executed once we’ve pulled the new tweets from Twitter.

function processTweets(data) {
  var len = data.length;
  for (var i = 0; i < len; i++) {
    if (data[i].id_str >= lastKnownTweetID) {
      lastKnownTweetID = data[i].id_str;
    }
  }
  returnTweets(data);
}

function returnTweets(data) {
  if (data.length > 0) {
    self.postMessage("Worker: New Tweets - " + data.length);
    self.postMessage(data);
  } else {
    self.postMessage("Worker: New Tweets - 0");
  }
  setTimeout(readTweets, updateDelay);
}

processTweets() enumerates all of the tweets we got back to find the most recent tweet ID. That way, when we ask Twitter again later for tweets, we’re only asking for the ones that we haven’t seen. Once we’ve done that, we call returnTweets() to push the new tweets back to the application. We could have merged processTweets() and returnTweets(), and I don’t remember why I decided to do it as two separate methods. Once we’re returned the tweets via returnTweets() we use setTimeout() to call readTweets() again.

A couple of quick tips

A couple things to remember about web workers, no DOM access means that you can’t manipulate the DOM, so that means that if you want to create new UI components in threads, you can, but you need to do it in the thread, and then pass that back to the main application via postMessage(). Unfortunately, it also means that jQuery doesn’t work in threads, so generating those UI components becomes a little more complex. I’ve heard rumors of a worker safe jQuery library, but haven’t seen it yet. Hopefully! :)

The other good thing to know is that you can debug works in the Chrome Developer Tools by clicking on the Scripts tab, and scrolling down in the column on the right to Workers and clicking on the debug checkbox.

Summary

I found using workers to be really easy, and a good way of handling this. There are plenty of other good ways to use workers – and it gives us some pretty good power to be able to push complex work down to the client. Especially as browsers JavaScript engines are getting faster and faster.

Additional Resources

HTML5_Performance_512

TweeterFall – Notifications

0

In TweeterFall, when a new tweet is received, we notify the user about that tweet via desktop notifications.  If you use Chrome and Gmail, you’ve probably seen notifications pop up when you receive a new mail, or about an upcoming appointment.  The Desktop Notifications API allows script to request a small toast to appear on the desktop of the user. The contents of the toast can either be specified as iconUrl/title/text strings, or as a URL to a remote resource which contains the contents of the toast. They’re part of the WebAPI spec, though still in early draft, and so far only implemented in Chrome.

Since notifications are still something that may change, in Chrome, they’re under the webkit vendor prefix. The Chromium implementation details can be found on the Chromium site.

There are two types of notifications that you can surface, what I’ll call simple notifications like the one on the left that contains an image, a headline and some text; and HTML notifications.  HTML notifications are much more powerful because instead of sending the image, headline and text, you send it a URL, and it will display the contents of that URL. That means you can style your notification to match your applications UI and even provide interactivity through links, javascript, etc.

Let’s have a look at how we implemented new tweet notifications in TweeterFall.

Requesting Permission

When the user turns on notifications in TweeterFall, we need to check to see if we have permission to show notifications and if we don’t we need to ask for it. Desktop Notifications pop open a new window and could quickly become an easy spam target if we didn’t provide some kind of permission system. When a user grants or denies permission, they do so for the domain.

function requestPermissionIfRequired() {
  if (!hasNotificationPermission() && (window.webkitNotifications)) {
    window.webkitNotifications.requestPermission();
  }
}

In requestPermissionIfRequired(), we check to see if the browser supports notifications, and if we already have permission. If we don’t have permission, but notifications are supported, Chrome prompts the user asking for permission to provide notifications.

Checking For Permission

I also use feature detection here to check to see if notifications are supported in the browser.  We will only return true if notifications are supported and the user has already given permission to show notifications.

function hasNotificationPermission() {
  return !!(window.webkitNotifications)
    && (window.webkitNotifications.checkPermission() == 0);
}

Show the Notification

We’re finally ready to show our notification to the user.

function showNotification(pic, title, text) {
  if (hasNotificationPermission()) {
    var notificationWindow =
      window.webkitNotifications.createNotification(pic, title, text);
    notificationWindow.show();
    setTimeout(function(notWin) {
      notWin.cancel();
    }, 10000, notificationWindow);
  } else {
    console.log("showNotification: No Permission");
  }
}

The method takes three parameters, the image to use, the title and the text do display. When the function is called, it checks to see if it has permission using our previously established permission check that also encompasses feature detection, so we know we’ll be safe calling this even if the browser doesn’t support notifications. We then create the notification with window.webkitNotifications.createNotification(pic, title, text) and show it with .show().

Immediately below that, we have a setTimeout call with an anonymous function that takes one parameter (the window handle to the notification) and will hide the notification after the timeout period has expired. If we didn’t do this, the notification would remain on screen until the user clicked the close button, or closed the browser. I’ve hard coded the timeout to be 10000ms, and you can change this to suit your needs.

Summary

As you can see, showing notifications is pretty easy, check & ask for permission, and then show the notification. You can use these to let the user know when a task is complete, when there’s new information that they might be interested in and so forth. Obviously these only work when a user is on your site, but you can overcome that limitation by publishing your app in the Chrome Web Store and using background pages.

Other Resources

Be sure to check out the notification tutorial on HTML5Rocks, it covers some additional things like the events that notifications fire and using HTML notifications.

HTML5_Logo_512.png

Building TweeterFall

0

I want to devote some time to how Ernest and I built TweeterFall, the demo that we used for our I/O Boot Camp presentation last week.  Instead of showing isolated demos of some of the new HTML5 features, we wanted to show how you might use some of these things in real world scenarios, and thus we built TweeterFall.  TweeterFall is a Twitter visualizer that grabs the tweets from a list and shows them in a kind of waterfall like visualization.

What did we use to build TweeterFall?

HTML5 Semantics

We used the new HTML5 semantic elements as our primary markup elements.  The bar across the top is a <header>, the area on the left where the tweets fall is a <section>, the list of Tweets on the right and the configuration panel are both <aside>’s, and the individual tweets are <article>s.

GeoLocation

Since we figured that most people would be in SF, it’d be fun to use some kind of geo location to show how close the person was to your current position when they made their Tweet.  To do that, we pull the users current location using navigator.geolocation.watchPosition and compare that to the geo data in the tweet.  We used the GeoLocation tutorial from HTML5Rocks.com as our inspiration for this.

IndexedDB

Twitter only allows you to pull about 20 tweets at a time, so if you want to see anything before that, you either need to log in (and we didn’t really want to deal with OAuth for this presentation) or store the previous tweets locally.  IndexedDB was the perfect solution for this, as it allows you to store significant quantities of structured data.  Figuring out IndexedDB was probably my biggest challenge for this project, mostly because it’s pretty new and there isn’t a lot of documentation on it yet.  That and the fact that everything you do is asynchronous, so you need lots of fun callbacks!  Look for a whole post on this one shortly.

LocalStorage

IndexedDB works great for structured data, but we also wanted a place to store simple configuration data, so we used web storage for that.  I wanted to have my configuration data in an object so I could easily access things, so I used JSON to parse and stringify my config object as it went into and came out of local storage.

Notifications

We used simple notifications to alert users when there were new tweets, and also included a special handler so that they would disappear after a couple of seconds and not remain on screen for too long.  One of the updates I want to make here is to use HTML notifications, so that we can make things look a little more like the rest of the UI.

Speech Input

Okay, so this one was a bit gratuitous. :)  If you add x-webkit-speech to text inputs, Chrome will add a microphone icon to the text box.  When the user clicks on the icon, Chrome turns on the microphone, listens for input and then converts what you said into text!  No JavaScript, just all magic!

Web Workers

Web Workers are great for handing off complex or intensive processes off to another thread so they don’t block the rest of the browser. In our case, we wanted to isolate the requests we were making to Twitter into their own place and allow them to “push” notifications to us.  One thing to remember with Web Workers, is that they run off in their own separate thread, and don’t have access to the DOM or most other window objects (which means jQuery won’t work either).

Canvas

This was a bit gratuitous too, we’ve got a fun update in mind for this that is equally gratuitous, but much prettier.

2D Transforms

When you mouse over the list of Tweets on the right, they get bigger to make them easier to read.  To do this, we use the :hover pseudo selector and apply a scale transform to make it bigger, and then a translation to ensure it appears in the right place.  If we didn’t do the translation, part of the tweet would get cut off on the right side.

CSS Animations

When I first created the TweeterFall visualization, I was using CSS transitions and transforms to animate the tweet as it fell down, but then realized that the better way to do it would be CSS Animations and transforms.

Web Fonts

We used Web Fonts to spice up the look of the page somewhat, there are lots of great fonts available.  Typically I’ll either grab fonts from Font Squirrel or Google’s Web Fonts.  As Ernest presented the section on web fonts, he said something to the effect of developers have had only 8 fonts they can count on across multiple platforms/browsers, and because Comic Sans doesn’t really count, they only really had 7.

Chrome Developer Tools

So we didn’t really use this in the app, but let me say this, the JavaScript console was the biggest life saver as we were debugging and trying to understand everything that was going on.  Not only did we use a few console.log’s, we also were able to execute code and do all kinds of other great things.  In fact, Paul Irish blogged about the I/O session he did with Pavel Feldman, and linked to the video - definitely worth checking out!

Up next, a dive into each of these!

bootcamp_logo

I/O Boot Camp – Getting Started With HTML5

0

Last week at I/O Boot Camp, Ernest Delgado and I presented a session titled Getting Started with HTML5.

Rather than take folks through the laundry list cool new stuff that’s part of HTML5, we took them through a smaller subset of features, showing how we used them in a real world application – TweeterFall.

You can watch the video, check out the slides and try TweeterFall.  When trying the slides, be sure to try them in Chrome dev, Canary or Safari to get the full 3D effects!

Pete's RSS Feed
Go to Top