Your SlideShare is downloading. ×
0
Jazz up your JavaScript
Unobtrusive scripting with JavaScript libraries

              Simon Willison
         Webstock, 1...
This tutorial


• Unobtrusive scripting
• JavaScript libraries
• Writing unobtrusive scripts with jQuery
But first... let’s travel
back in time to 2004
(The only photo I could find of me in 2004)
JavaScript was the ugly duckling of the web standards world
Animated snowflakes
DHTML scripts copied and pasted from dynamicdrive.com
3 revolutions since 2004

•
    Ajax
• Unobtrusive scripting
• High quality open-source libraries
February 2005
The quieter revolutions
were just as important
Unobtrusive Scripting
Progressive enhancement
Rather than hoping for graceful degradation, PE
builds documents for the least capable or
differen...
Applied to JavaScript

• Build a site that works without JavaScript
• Use JavaScript to enhance that site to
  provide a b...
http://www.neighbourhoodfixit.com/
• Start with Plain Old Semantic HTML
• Layer on some CSS (in an external
  stylesheet) to apply the site’s visual design

...
Surely everyone has
JavaScript these days?
• There are legitimate reasons to switch it off
 • Some companies strip JavaScript at the
    firewall

  • Some people run...
The NoScript extension
Unobtrusive examples
labels.js




• One of the earliest examples of this
  technique, created by Aaron Boodman (now
  of Greasemonkey and Goog...
How it works
         <label for=quot;searchquot;>Search</label>
         <input type=quot;textquot; id=quot;searchquot; n...
easytoggle.js
  • An unobtrusive technique for revealing
     panels when links are clicked

<ul>
  <li><a href=quot;#pane...
How it works
•   When the page has loaded...

    •   Find all links with class=quot;togglequot; that reference an
       ...
Django filter lists

• Large multi-select boxes aren't much fun
 • Painful to scroll through
 • Easy to lose track of what ...
Mapping Microformats

• The hCard microformat provides a standard
  set of CSS classes for marking up an address
• Wouldn’...
•   When the page loads...

    •   Scan through for hCards (by looking for
        class=quot;vCardquot;)

    •   Extrac...
How about Ajax?
• Ajax is frequently used to avoid page refreshes
• So...
 • Write an app that uses full page refreshes
 •...
A simple example
Bad

Have you read our
<a href=quot;javascript:window.open(
   'terms.html', 'popup',
   'height=500,width=400,toolbar=no'...
Also bad

Have you read our
<a href=quot;#quot; onclick=quot;window.open(
   'terms.html', 'popup',
   'height=500,width=4...
Better

Have you read our
<a href=quot;terms.htmlquot;
 onclick=quot;window.open(
   'terms.html', 'popup',
   'height=500...
Better still

Have you read our
<a href=quot;terms.htmlquot;
 onclick=quot;window.open(
   this.href, 'popup',
   'height=...
Best

Have you read our
<a href=quot;terms.htmlquot;
  class=quot;sidenotequot;
>terms and conditions</a>?
Characteristics of
   unobtrusive scripts
• No in-line event handlers
• All code is contained in external .js files
• The s...
Handling events

function makeLinkPopup(link) {
    if (link.addEventListener) { // W3C spec browsers
	

   link.addEventL...
Handling events (2)
function popupClicked(ev) {
    // Find the link that was clicked
    ev = ev || window.event;
    var...
Handling events (3)
function setupLinks() {
  var links = document.getElementsByTagName('a');
  for (var i = 0, link; link...
That’s way too much
  nasty boilerplate
Unobtrusive challenges
• Adding events from pure script (avoiding
  inline script handlers) works differently
  between IE...
The onload problem
• All of these examples use code that runs
  when the window quot;loadquot; event is fired
  • Wait unti...
onDOMReady
•   A number of attempts have been made to create
    an onDOMReady event that fires when the
    DOM has been c...
So we need libraries

• Writing this stuff by hand is madness
• Boilerplate code to deal with browser
  inconsistencies is...
JavaScript Libraries
Controversial statement

• A year ago, there was a sizable debate over
    whether libraries were worth using at all -
   ...
“The bad news:
JavaScript is broken.
    The good news:
 It can be fixed with
  more JavaScript!”
              Geek folk s...
JavaScript characteristics
• Highly dynamic language
 • Most things can be introspected
 • Most things can be modified at r...
Modifying built-in types

var s = quot;This is a stringquot;;
alert(s.dasherize()); // Throws an error

String.prototype.d...
Functional programming
function hello() {
  alert(quot;helloquot;);
}

var hello = function() {
  alert(quot;helloquot;);
...
Functional programming
function hello() {
  alert(quot;helloquot;);
}

var hello = function() {
  alert(quot;helloquot;);
...
Functional programming
function hello() {
  alert(quot;helloquot;);
}

var hello = function() {
  alert(quot;helloquot;);
...
Closures

function outer() {
  var s = quot;This is a stringquot;;
  function inner() {
    alert(s);
  }
  inner();
}
Closures

function outer() {
  var s = quot;This is a stringquot;;
  function inner() {
    alert(s);
  }
  return inner;
...
Closures
function outer(s) {
  function inner() {
    alert(s);
  }
  return inner;
}

var sayHello = outer(quot;Helloquot...
Common library
   features
DOM selection


• document.getElementById shortcut
• Get elements by class name
• Get elements by CSS selector
CSS manipulation


• Manipulate and toggle classes
• Set styles (including opacity)
• Introspect applied styles
Event handling
• Cross-browser “run this function when this
  event happens to this element”
• Cross-browser “on DOM ready...
Ajax

• Cross-browser XMLHttpRequest
• Easier API for GET, POST and URL and form
  manipulation
• Support for Ajax formats...
Effects and animation

• Fades, wipes and transitions
• Custom animation of any CSS property
• Automatic frame-rate manage...
Widgets
• Packaged widgets for things like...
 • Sliders
 • Calendar date pickers
 • Fake “windows”
 • Auto-completers
 • ...
Language tools

• Iteration over objects and arrays
• Utilities for managing prototypal inheritance
• Traditional class-ba...
Array manipulation
for (var i = 0; i < arr.length; i++) {
   var item = arr[i];
   // process item
}

forEach(arr, functio...
Other characteristics
• Do they modify built in types?
• Global namespace impact
• Library size and componentization
• Sup...
The big five
• The Yahoo! User Interface Library
• Prototype (and Script.aculo.us)
• The Dojo Toolkit
• mooTools
• jQuery
The Example

• A login form that shakes its head at you
• Standard POST login form, unobtrusively
  upgraded to use Ajax a...
Simple login JSON API
• Responds to the same POST as the regular
   form, but looks for X-Requested-With:
   XMLHttpReques...
The Yahoo! User Interface Library
controls (aka widgets)

autocomplete           calendar           container


  menu                slider            tree...
YAHOO.util.Event.onDOMReady(function() {
    var $E = YAHOO.util.Event;
    var $D = YAHOO.util.Dom;
    var $C = YAHOO.ut...
YAHOO.util.Event.onDOMReady(function() {
    var $E = YAHOO.util.Event;
    var $D = YAHOO.util.Dom;
    var $C = YAHOO.ut...
YAHOO.util.Event.onDOMReady(function() {
    var $E = YAHOO.util.Event;
    var $D = YAHOO.util.Dom;
    var $C = YAHOO.ut...
YAHOO.util.Event.onDOMReady(function() {
    var $E = YAHOO.util.Event;
    var $D = YAHOO.util.Dom;
    var $C = YAHOO.ut...
$E.on(form, 'submit', function(ev) {
    $E.preventDefault(ev);
    var url = form.action;
    $C.setForm(form);
    $C.as...
success: function(response) {
  var json = eval('(' +
    response.responseText + ')');
  if (json.ok) {
    window.locati...
function shake(el, onComplete) {
    var $D = YAHOO.util.Dom;
    $D.setStyle(el, 'position', 'relative');
    var anim = ...
function shake(el, onComplete) {
    var $D = YAHOO.util.Dom;
    $D.setStyle(el, 'position', 'relative');
    var anim = ...
• Nice animation library, but a better way of
  chaining animations would be useful

• Severe namespacing (YAHOO was picke...
Download
                                                            Get the latest version—1.5.1


                      ...
document.observe('dom:loaded', function() {
    $('username').focus();
    var form = $$('form')[0];
    form.observe('sub...
onSuccess: function(response) {
    var json = response.responseJSON;
    if (json.ok) {
        window.location = json.re...
• Adds many functions to the global
  namespace ($, $$ etc) and extensively
  modifies built in types

• Heavily inspired b...
The Dojo Toolkit
dojo.require('dojox.fx');
djConfig.usePlainJson = true;

dojo.addOnLoad(function() {
  dojo.byId('username').focus();
  do...
load: function(json) {
  if (json.ok) {
    window.location = json.redirect;
  } else {
    form.style.position = 'relativ...
dojo.connect(last, 'onEnd', function() {
  if (!dojo.query('p.error').length) {
    var p = document.createElement('p');
 ...
• core, dijit and dojox:
 • Small, powerful abstraction library
 • Widget creation tools plus many widgets
 • “The future ...
mooTools
window.addEvent('domready', function() {
    $('username').focus();
    $$('form').addEvent('submit', function(ev) {
     ...
var fx = form.effects({
    duration: 100,
    transition: Fx.Transitions.Quart.easeOut
});
fx.start({left: -10}).chain(fu...
•   Started as an effects library for Prototype, now its
    own thing but Prototype influences are clear

•   No intention...
jQuery
jQuery(function($) {
  $('#username').focus();
  $('form').submit(function() {
    var $this = $(this);
    var url = $thi...
jQuery.fn.shake = function(callback) {
    this.css({'position': 'relative'});
    return this.animate(
        {left: '-1...
• Powerful, concise API based around CSS
  selector querying and chaining

• Excellent namespace management -
  everything...
Unobtrusive scripting
   with jQuery
Why jQuery

• It has the best balance between simplicity,
  productivity and good manners
• It has excellent documentation...
Why jQuery instead of...?

•   Unlike Prototype and mooTools...

    •   ... it doesn’t populate your global namespace

• ...
Learning

jQuery
in 45 minutes
jQuery philosophy

• Focus on the interaction between JavaScript
  and HTML
• (Almost) every operation boils down to:
 • F...
Sidenotes with jQuery

jQuery(function($) {
  $('a.sidenote').click(function() {
    window.open($(this).attr('href'), 'po...
Only one function!
• Absolutely everything* starts with a call to
  the jQuery() function
• Since it’s called so often, th...
jQuery('#nav')

jQuery('div#intro h2')

jQuery('#nav li.current a')
$('#nav')

$('div#intro h2')

$('#nav li.current a')
CSS 2 and 3 selectors

a[rel]

a[rel=quot;friendquot;]

a[href^=quot;http://quot;]

ul#nav > li

li#current ~ li (li sibli...
Magic selectors
div:first, h3:last
:header
:hidden, :visible
:animated
:input, :text, :password, :radio, :submit...
div:co...
jQuery collections
 •   $('div.section') returns a jQuery collection


 •   You can treat it like an array
$('div.section'...
jQuery collections
 •    $('div.section') returns a jQuery collection


 •    You can call methods on it
$('div.section')....
jQuery collections
 •    $('div.section') returns a jQuery collection


 •    You can call methods on it
$('div.section')....
HTML futzing


$('span#msg').text('The thing was updated!');



$('div#intro').html('<em>Look, HTML</em>');
Attribute futzing

$('a.nav').attr('href', 'http://flickr.com/');

$('a.nav').attr({

  'href': 'http://flickr.com/',

  '...
CSS futzing

$('#intro').addClass('highlighted');

$('#intro').removeClass('highlighted');

$('#intro').toggleClass('highl...
Grabbing values
 • Some methods return results from the first
    matched element
var height = $('div#intro').height();

va...
Traversing the DOM
 • jQuery provides enhanced methods for
    traversing the DOM
$('div.section').parent()

$('div.sectio...
Handling events

$('a:first').click(function(ev) {

  $(this).css({backgroundColor: 'orange'});

  return false; // Or ev....
Handling events

$('a:first').click(function(ev) {

  $(this).css({backgroundColor: 'orange'});

  return false; // Or ev....
Going unobtrusive


$(document).ready(function() {

  alert('The DOM is ready!');

});
Going unobtrusive


$(function() {

  alert('The DOM is ready!');

});
Going unobtrusive


jQuery(function($) {

  alert('The DOM is ready!');

});
Chaining

 • Most jQuery methods return another
    jQuery object - usually one representing the
    same collection. This...
Advanced chaining
• Some methods return a different collection
• You can call .end() to revert to the previous
  collection
Advanced chaining

 • Some methods return a different collection
 • You can call .end() to revert to the previous
    coll...
Ajax
 •   jQuery has excellent support for Ajax
$('div#intro').load('/some/file.html');

 •   More advanced methods includ...
Animation

 • jQuery has built in effects:
$('h1').hide('slow');

$('h1').slideDown('fast');

$('h1').fadeOut(2000);

 • Y...
Or roll your own...

$(quot;#blockquot;).animate({

   width: quot;+=60pxquot;,

   opacity: 0.4,

   fontSize: quot;3emqu...
Plugins


• jQuery is extensible through plugins, which
  can add new methods to the jQuery object
Further reading
• http://jquery.com/
• http://docs.jquery.com/
• http://visualjquery.com/ - API reference
• http://simonwi...
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Upcoming SlideShare
Loading in...5
×

Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries

8,667

Published on

Slides from a three hour tutorial presented at Webstock in February 2008.

Published in: Technology
0 Comments
22 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
8,667
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
329
Comments
0
Likes
22
Embeds 0
No embeds

No notes for slide

Transcript of "Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries"

  1. 1. Jazz up your JavaScript Unobtrusive scripting with JavaScript libraries Simon Willison Webstock, 11th February 2008
  2. 2. This tutorial • Unobtrusive scripting • JavaScript libraries • Writing unobtrusive scripts with jQuery
  3. 3. But first... let’s travel back in time to 2004
  4. 4. (The only photo I could find of me in 2004)
  5. 5. JavaScript was the ugly duckling of the web standards world
  6. 6. Animated snowflakes
  7. 7. DHTML scripts copied and pasted from dynamicdrive.com
  8. 8. 3 revolutions since 2004 • Ajax • Unobtrusive scripting • High quality open-source libraries
  9. 9. February 2005
  10. 10. The quieter revolutions were just as important
  11. 11. Unobtrusive Scripting
  12. 12. Progressive enhancement Rather than hoping for graceful degradation, PE builds documents for the least capable or differently capable devices first, then moves on to enhance those documents with separate logic for presentation, in ways that don't place an undue burden on baseline devices but which allow a richer experience for those users with modern graphical browser software. Steven Champeon and Nick Finck, 2003
  13. 13. Applied to JavaScript • Build a site that works without JavaScript • Use JavaScript to enhance that site to provide a better user experience: easier to interact with, faster, more fun
  14. 14. http://www.neighbourhoodfixit.com/
  15. 15. • Start with Plain Old Semantic HTML • Layer on some CSS (in an external stylesheet) to apply the site’s visual design • Layer on some JavaScript (in an external script file) to apply the site’s enhanced behaviour
  16. 16. Surely everyone has JavaScript these days?
  17. 17. • There are legitimate reasons to switch it off • Some companies strip JavaScript at the firewall • Some people run the NoScript Firefox extension to protect themselves from common XSS and CSRF vulnerabilities • Many mobile devices ignore JS entirely • Screen readers DO execute JavaScript, but accessibility issues mean that you may not want them to
  18. 18. The NoScript extension
  19. 19. Unobtrusive examples
  20. 20. labels.js • One of the earliest examples of this technique, created by Aaron Boodman (now of Greasemonkey and Google Gears fame)
  21. 21. How it works <label for=quot;searchquot;>Search</label> <input type=quot;textquot; id=quot;searchquot; name=quot;qquot;> • Once the page has loaded, the JavaScript: • Finds any label elements linked to a text field • Moves their text in to the associated text field • Removes them from the DOM • Sets up the event handlers to remove the descriptive text when the field is focused • Clean, simple, reusable
  22. 22. easytoggle.js • An unobtrusive technique for revealing panels when links are clicked <ul> <li><a href=quot;#panel1quot; class=quot;togglequot;>Panel 1</a></li> <li><a href=quot;#panel2quot; class=quot;togglequot;>Panel 2</a></li> <li><a href=quot;#panel3quot; class=quot;togglequot;>Panel 3</a></li> </ul> <div id=quot;panel1quot;>...</div> <div id=quot;panel2quot;>...</div> <div id=quot;panel3quot;>...</div>
  23. 23. How it works • When the page has loaded... • Find all links with class=quot;togglequot; that reference an internal anchor • Collect the elements that are referenced by those anchors • Hide all but the first • Set up event handlers to reveal different panels when a link is clicked • Without JavaScript, links still jump to the right point
  24. 24. Django filter lists • Large multi-select boxes aren't much fun • Painful to scroll through • Easy to lose track of what you have selected • Django's admin interface uses unobtrusive JavaScript to improve the usability here
  25. 25. Mapping Microformats • The hCard microformat provides a standard set of CSS classes for marking up an address • Wouldn’t it be great if we could unobtrusively plot them on a Google Map...
  26. 26. • When the page loads... • Scan through for hCards (by looking for class=quot;vCardquot;) • Extract the street address and postcode for each one • Pass it to the Google Maps geocoder to get the lat/long point • Insert a div for the Google Map, instantiate it and add the points as markers
  27. 27. How about Ajax? • Ajax is frequently used to avoid page refreshes • So... • Write an app that uses full page refreshes • Use unobtrusive JS to quot;hijackquot; links and form buttons and use Ajax instead • Jeremy Keith coined the term quot;Hijaxquot; to describe this
  28. 28. A simple example
  29. 29. Bad Have you read our <a href=quot;javascript:window.open( 'terms.html', 'popup', 'height=500,width=400,toolbar=no' );quot;>terms and conditions</a>?
  30. 30. Also bad Have you read our <a href=quot;#quot; onclick=quot;window.open( 'terms.html', 'popup', 'height=500,width=400,toolbar=no' ); return false;quot; >terms and conditions</a>?
  31. 31. Better Have you read our <a href=quot;terms.htmlquot; onclick=quot;window.open( 'terms.html', 'popup', 'height=500,width=400,toolbar=no' ); return false;quot; >terms and conditions</a>?
  32. 32. Better still Have you read our <a href=quot;terms.htmlquot; onclick=quot;window.open( this.href, 'popup', 'height=500,width=400,toolbar=no' ); return false;quot; >terms and conditions</a>?
  33. 33. Best Have you read our <a href=quot;terms.htmlquot; class=quot;sidenotequot; >terms and conditions</a>?
  34. 34. Characteristics of unobtrusive scripts • No in-line event handlers • All code is contained in external .js files • The site remains usable without JavaScript • Existing links and forms are repurposed • JavaScript dependent elements are dynamically added to the page
  35. 35. Handling events function makeLinkPopup(link) { if (link.addEventListener) { // W3C spec browsers link.addEventListener('click', popupClicked, false); } else if (link.attachEvent) { // Internet Explorer link.attachEvent('onclick', popupClicked); } else { return; // Fail silently in ancient browsers } }
  36. 36. Handling events (2) function popupClicked(ev) { // Find the link that was clicked ev = ev || window.event; var link = ev.target || ev.srcElement; if (link.nodeType == 3) { // Safari bug fix link = link.parentNode; } window.open(link.href, 'popup', 'height=500,width=400,toolbar=no'); // Now prevent the default link action if (ev.preventDefault) { ev.preventDefault(); // W3C spec browsers } else { ev.returnValue = false; // Internet Explorer } }
  37. 37. Handling events (3) function setupLinks() { var links = document.getElementsByTagName('a'); for (var i = 0, link; link = links[i]; i++) { if (link.className == 'sidenote') { makeLinkPopup(link); } } } if (window.addEventListener) { window.addEventListener('load', setupLinks, false); } else if (window.attachEvent) { window.attachEvent('onload', setupLinks); }
  38. 38. That’s way too much nasty boilerplate
  39. 39. Unobtrusive challenges • Adding events from pure script (avoiding inline script handlers) works differently between IE and other browsers • Cancelling default actions (link navigation, form submission) also works differently • Scripts that add behaviour need to execute as soon as the DOM is available
  40. 40. The onload problem • All of these examples use code that runs when the window quot;loadquot; event is fired • Wait until page is loaded, then manipulate the DOM • Problem: If the page takes a while to load (large inline images) there will be a Flash Of Unstyled Content (FOUC) • Also, if the user clicks things before the setup code has fired they won't get the expected behaviour.
  41. 41. onDOMReady • A number of attempts have been made to create an onDOMReady event that fires when the DOM has been constructed but before the page has loaded • dean.edwards.name/weblog/2006/06/again/ • Modern libraries all support this in some form • One caveat: CSS may not have loaded, so calculated dimensions may be incorrect
  42. 42. So we need libraries • Writing this stuff by hand is madness • Boilerplate code to deal with browser inconsistencies is the number one enemy of unobtrusive scripting • Thankfully, today these are all solved problems
  43. 43. JavaScript Libraries
  44. 44. Controversial statement • A year ago, there was a sizable debate over whether libraries were worth using at all - many people preferred to just “roll their own” • Today, that argument is over. Libraries have won. • (some may disagree)
  45. 45. “The bad news: JavaScript is broken. The good news: It can be fixed with more JavaScript!” Geek folk saying
  46. 46. JavaScript characteristics • Highly dynamic language • Most things can be introspected • Most things can be modified at runtime • Functional programming, anonymous functions and closures • Ability to modify behaviour of built-in types • Prototypal inheritance - arguably more powerful than class-based inheritance, though much less widely understood
  47. 47. Modifying built-in types var s = quot;This is a stringquot;; alert(s.dasherize()); // Throws an error String.prototype.dasherize = function() { return this.toLowerCase().replace(/s+/g, '-'); } alert(s.dasherize()); // this-is-a-string
  48. 48. Functional programming function hello() { alert(quot;helloquot;); } var hello = function() { alert(quot;helloquot;); } (function() { alert(quot;helloquot;); })();
  49. 49. Functional programming function hello() { alert(quot;helloquot;); } var hello = function() { alert(quot;helloquot;); } (function() { alert(quot;helloquot;); })();
  50. 50. Functional programming function hello() { alert(quot;helloquot;); } var hello = function() { alert(quot;helloquot;); } (function() { alert(quot;helloquot;); })();
  51. 51. Closures function outer() { var s = quot;This is a stringquot;; function inner() { alert(s); } inner(); }
  52. 52. Closures function outer() { var s = quot;This is a stringquot;; function inner() { alert(s); } return inner; } var func = outer(); func(); // Alerts quot;This is a stringquot;;
  53. 53. Closures function outer(s) { function inner() { alert(s); } return inner; } var sayHello = outer(quot;Helloquot;); var sayGoodbye = outer(quot;Goodbyequot;); sayHello(); sayGoodbye();
  54. 54. Common library features
  55. 55. DOM selection • document.getElementById shortcut • Get elements by class name • Get elements by CSS selector
  56. 56. CSS manipulation • Manipulate and toggle classes • Set styles (including opacity) • Introspect applied styles
  57. 57. Event handling • Cross-browser “run this function when this event happens to this element” • Cross-browser “on DOM ready” support • Cross-browser event introspection: where was the event targetted? • Event triggering • Custom events
  58. 58. Ajax • Cross-browser XMLHttpRequest • Easier API for GET, POST and URL and form manipulation • Support for Ajax formats: HTML fragments, JSON, XML
  59. 59. Effects and animation • Fades, wipes and transitions • Custom animation of any CSS property • Automatic frame-rate management • Easing
  60. 60. Widgets • Packaged widgets for things like... • Sliders • Calendar date pickers • Fake “windows” • Auto-completers • Grids and treeviews • Support for drag-and-drop
  61. 61. Language tools • Iteration over objects and arrays • Utilities for managing prototypal inheritance • Traditional class-based inheritance • Tools for managing scope and callbacks • Dynamic code loading
  62. 62. Array manipulation for (var i = 0; i < arr.length; i++) { var item = arr[i]; // process item } forEach(arr, function(item) { // process item }); doubles = map(arr, function(i) { return i * 2 }); evens = filter(arr, function(i) { return i % 2 == 0 });
  63. 63. Other characteristics • Do they modify built in types? • Global namespace impact • Library size and componentization • Support for accessibility (esp. for widgets) • Browser support • Documentation • Community
  64. 64. The big five • The Yahoo! User Interface Library • Prototype (and Script.aculo.us) • The Dojo Toolkit • mooTools • jQuery
  65. 65. The Example • A login form that shakes its head at you • Standard POST login form, unobtrusively upgraded to use Ajax and shake if the password is incorrect • Behind the scenes, JSON is used for the reply to say if the password was correct or not
  66. 66. Simple login JSON API • Responds to the same POST as the regular form, but looks for X-Requested-With: XMLHttpRequest header • If login fails, returns {quot;okquot;:false} • If login succeeds, returns {quot;okquot;: true, quot;redirectquot;: quot;loggedin.phpquot;}
  67. 67. The Yahoo! User Interface Library
  68. 68. controls (aka widgets) autocomplete calendar container menu slider treeview animation dragdrop dom event connection utilities
  69. 69. YAHOO.util.Event.onDOMReady(function() { var $E = YAHOO.util.Event; var $D = YAHOO.util.Dom; var $C = YAHOO.util.Connect; var query = YAHOO.util.Selector.query; $D.get('username').focus(); var form = query('form')[0];
  70. 70. YAHOO.util.Event.onDOMReady(function() { var $E = YAHOO.util.Event; var $D = YAHOO.util.Dom; var $C = YAHOO.util.Connect; var query = YAHOO.util.Selector.query; $D.get('username').focus(); var form = query('form')[0];
  71. 71. YAHOO.util.Event.onDOMReady(function() { var $E = YAHOO.util.Event; var $D = YAHOO.util.Dom; var $C = YAHOO.util.Connect; var query = YAHOO.util.Selector.query; $D.get('username').focus(); var form = query('form')[0];
  72. 72. YAHOO.util.Event.onDOMReady(function() { var $E = YAHOO.util.Event; var $D = YAHOO.util.Dom; var $C = YAHOO.util.Connect; var query = YAHOO.util.Selector.query; $D.get('username').focus(); var form = query('form')[0];
  73. 73. $E.on(form, 'submit', function(ev) { $E.preventDefault(ev); var url = form.action; $C.setForm(form); $C.asyncRequest( 'POST', url, { success: function() { ... } } ); });
  74. 74. success: function(response) { var json = eval('(' + response.responseText + ')'); if (json.ok) { window.location = json.redirect; } else { $D.get('password').value = ''; $D.get('password').focus(); shake(form, function() { if (!query('p.error').length) { var p = document.createElement('p'); p.className = 'error'; p.innerHTML = 'Incorrect password.'; form.insertBefore(p, form.firstChild); } }); }
  75. 75. function shake(el, onComplete) { var $D = YAHOO.util.Dom; $D.setStyle(el, 'position', 'relative'); var anim = new YAHOO.util.Anim(el, { left: {to: -10} }, 0.1, YAHOO.util.Easing.easeOut); anim.onComplete.subscribe(function() { // ... } anim.animate(); }
  76. 76. function shake(el, onComplete) { var $D = YAHOO.util.Dom; $D.setStyle(el, 'position', 'relative'); var anim = new YAHOO.util.Anim(el, { left: {to: -10} }, 0.1, YAHOO.util.Easing.easeOut); anim.onComplete.subscribe(function() { var anim2 = new YAHOO.util.Anim(el, { left: {to: 10} }, 0.1, YAHOO.util.Easing.easeOut); anim2.onComplete.subscribe(function() { var anim3 = new YAHOO.util.Anim(el, { left: {to: -10} }, 0.1, YAHOO.util.Easing.easeOut); anim3.onComplete.subscribe(function() { var anim4 = new YAHOO.util.Anim(el, { left: {to: 10} }, 0.1, YAHOO.util.Easing.easeOut); anim4.onComplete.subscribe(function() { var anim5 = new YAHOO.util.Anim(el, { left: {to: 0} }, 0.1, YAHOO.util.Easing.easeOut); if (onComplete) { anim5.onComplete.subscribe(onComplete); } anim5.animate(); }); anim4.animate(); }); anim3.animate(); }); anim2.animate(); }); anim.animate(); }
  77. 77. • Nice animation library, but a better way of chaining animations would be useful • Severe namespacing (YAHOO was picked because it was so ugly no one would ever have used it for an existing variable) • Not too many shortcuts outside of dealing with browser difficulties • Excellent documentation
  78. 78. Download Get the latest version—1.5.1 Learn Prototype is a JavaScript Framework that aims to Online documentation and resources. ease development of dynamic web applications. Featuring a unique, easy-to-use toolkit for class-driven Discuss development and the nicest Ajax library around, Prototype Mailing list and IRC is quickly becoming the codebase of choice for web application developers everywhere. Contribute Prototype and Script.aculo.us Prototype and script.aculo.us: The quot;Bungee bookquot; has landed! Submit patches and report bugs. Who's using Prototype? Meet the developers Core team member Christophe Porteneuve has been hard at work for the past few months tracking
  79. 79. document.observe('dom:loaded', function() { $('username').focus(); var form = $$('form')[0]; form.observe('submit', function(ev) { ev.preventDefault(); var url = form.action; new Ajax.Request(url, { parameters: form.serialize(), onSuccess: ... }); }); });
  80. 80. onSuccess: function(response) { var json = response.responseJSON; if (json.ok) { window.location = json.redirect; } else { form.shake(); // No apparent way of setting an // quot;on finishedquot; callback setTimeout(function() { if (!$$('p.error').length) { var p = new Element( 'p', {'class': 'error'} ).insert('Incorrect...'); form.insertBefore(p, form.firstChild); } }, 500); $('password').value = ''; $('password').focus(); } }
  81. 81. • Adds many functions to the global namespace ($, $$ etc) and extensively modifies built in types • Heavily inspired by Ruby and Ruby on Rails • Useful shortcuts and nice effects • Documentation still leaves something to be desired - API docs for Prototype, incomplete wiki docs for Scriptaculous
  82. 82. The Dojo Toolkit
  83. 83. dojo.require('dojox.fx'); djConfig.usePlainJson = true; dojo.addOnLoad(function() { dojo.byId('username').focus(); dojo.query('form').connect('submit', function(ev) { dojo.stopEvent(ev); var form = this; var url = form.action; dojo.xhrPost({ handleAs: 'json', headers: {'X-Requested-With': 'XMLHttpRequest'}, url: url, form: form, load: function(json) { ... } }); }); });
  84. 84. load: function(json) { if (json.ok) { window.location = json.redirect; } else { form.style.position = 'relative'; var last = dojo.animateProperty({ node: form, duration: 100, properties: {left: {end: 0}} }); var leftArgs = { node: form, duration: 100, properties: {left: {end: -10}} }; var rightArgs = { node: form, duration: 100, properties: {left: {end: 10}} }; dojo.fx.chain([ dojo.animateProperty(leftArgs), dojo.animateProperty(rightArgs), dojo.animateProperty(leftArgs), dojo.animateProperty(rightArgs), last ]).play();
  85. 85. dojo.connect(last, 'onEnd', function() { if (!dojo.query('p.error').length) { var p = document.createElement('p'); p.className = 'error'; p.innerHTML = 'Incorrect username or password.'; form.insertBefore(p, form.firstChild); } }); dojo.byId('password').value = ''; dojo.byId('password').focus();
  86. 86. • core, dijit and dojox: • Small, powerful abstraction library • Widget creation tools plus many widgets • “The future today” genius extensions • Documentation has improved with the Dojo Book, but still patchy in places
  87. 87. mooTools
  88. 88. window.addEvent('domready', function() { $('username').focus(); $$('form').addEvent('submit', function(ev) { new Event(ev).stop(); var form = this; var url = form.action; form.send({ onComplete: function(data) { var json = Json.evaluate(data); if (json.ok) { window.location = json.redirect; } else { form.style.position = 'relative'; // ... animation here $('password').value = ''; $('password').focus(); } } }); }); });
  89. 89. var fx = form.effects({ duration: 100, transition: Fx.Transitions.Quart.easeOut }); fx.start({left: -10}).chain(function(){ this.start({left: 10}); }).chain(function(){ this.start({left: -10}); }).chain(function(){ this.start({left: 10}); }).chain(function(){ this.start({left: 0}); }).chain(function() { if (!$$('p.error').length) { var p = new Element('p'). addClass('error').setHTML( 'Incorrect username or password.' ); form.insertBefore(p, form.firstChild); } });
  90. 90. • Started as an effects library for Prototype, now its own thing but Prototype influences are clear • No intention at all of playing nicely with other libraries • Good API documentation (including a mootorial) but not much else, and major changes between library versions • I found the API unintuitive compared to the others
  91. 91. jQuery
  92. 92. jQuery(function($) { $('#username').focus(); $('form').submit(function() { var $this = $(this); var url = $this.attr('action'); var data = $this.serialize(); jQuery.post(url, data, function(json) { if (json.ok) { window.location = json.redirect; } else { $('#password').val('').focus(); $this.shake(function() { if (!$this.find('p.error').length) { $this.prepend('<p class=quot;errorquot;>Incorrect ...</p>'); } }); } }, 'json'); return false; }); });
  93. 93. jQuery.fn.shake = function(callback) { this.css({'position': 'relative'}); return this.animate( {left: '-10px'}, 100 ).animate( {left: '+10px'}, 100 ).animate( {left: '-10px'}, 100 ).animate( {left: '+10px'}, 100 ).animate( {left: '0px'}, 100, callback ); };
  94. 94. • Powerful, concise API based around CSS selector querying and chaining • Excellent namespace management - everything lives on the one jQuery symbol which is aliased to $, with the option to revert • Excellent support for plugins • The best documentation out of all of the libraries
  95. 95. Unobtrusive scripting with jQuery
  96. 96. Why jQuery • It has the best balance between simplicity, productivity and good manners • It has excellent documentation • You can learn the whole library in less than an hour
  97. 97. Why jQuery instead of...? • Unlike Prototype and mooTools... • ... it doesn’t populate your global namespace • Unlike YUI... • ... it’s extremely succinct • Unlike Dojo... • ... you can learn it in 45 minutes!
  98. 98. Learning jQuery in 45 minutes
  99. 99. jQuery philosophy • Focus on the interaction between JavaScript and HTML • (Almost) every operation boils down to: • Find some stuff • Do something to it
  100. 100. Sidenotes with jQuery jQuery(function($) { $('a.sidenote').click(function() { window.open($(this).attr('href'), 'popup', 'height=500,width=400,toolbar=no'); return false; }); });
  101. 101. Only one function! • Absolutely everything* starts with a call to the jQuery() function • Since it’s called so often, the $ variable is set up as an alias to jQuery • If you’re also using another library you can revert to the previous $ function with jQuery.noConflict(); * not entirely true
  102. 102. jQuery('#nav') jQuery('div#intro h2') jQuery('#nav li.current a')
  103. 103. $('#nav') $('div#intro h2') $('#nav li.current a')
  104. 104. CSS 2 and 3 selectors a[rel] a[rel=quot;friendquot;] a[href^=quot;http://quot;] ul#nav > li li#current ~ li (li siblings that follow #current) li:first-child, li:last-child, li:nth-child(3)
  105. 105. Magic selectors div:first, h3:last :header :hidden, :visible :animated :input, :text, :password, :radio, :submit... div:contains(Hello)
  106. 106. jQuery collections • $('div.section') returns a jQuery collection • You can treat it like an array $('div.section').length = no. of matched elements $('div.section')[0] - the first div DOM element $('div.section')[1] $('div.section')[2]
  107. 107. jQuery collections • $('div.section') returns a jQuery collection • You can call methods on it $('div.section').size() = no. of matched elements $('div.section').each(function() { console.log(this); });
  108. 108. jQuery collections • $('div.section') returns a jQuery collection • You can call methods on it $('div.section').size() = no. of matched elements $('div.section').each(function(i) { console.log(quot;Item quot; + i + quot; is quot;, this); });
  109. 109. HTML futzing $('span#msg').text('The thing was updated!'); $('div#intro').html('<em>Look, HTML</em>');
  110. 110. Attribute futzing $('a.nav').attr('href', 'http://flickr.com/'); $('a.nav').attr({ 'href': 'http://flickr.com/', 'id': 'flickr' }); $('#intro').removeAttr('id');
  111. 111. CSS futzing $('#intro').addClass('highlighted'); $('#intro').removeClass('highlighted'); $('#intro').toggleClass('highlighted'); $('p').css('font-size', '20px'); $('p').css({'font-size': '20px', color: 'red'});
  112. 112. Grabbing values • Some methods return results from the first matched element var height = $('div#intro').height(); var src = $('img.photo').attr('src'); var lastP = $('p:last').html() var hasFoo = $('p').hasClass('foo'); var email = $('input#email').val();
  113. 113. Traversing the DOM • jQuery provides enhanced methods for traversing the DOM $('div.section').parent() $('div.section').next() $('div.section').prev() $('div.section').nextAll('div') $('h1:first').parents()
  114. 114. Handling events $('a:first').click(function(ev) { $(this).css({backgroundColor: 'orange'}); return false; // Or ev.preventDefault(); });
  115. 115. Handling events $('a:first').click(function(ev) { $(this).css({backgroundColor: 'orange'}); return false; // Or ev.preventDefault(); }); $('a:first').click();
  116. 116. Going unobtrusive $(document).ready(function() { alert('The DOM is ready!'); });
  117. 117. Going unobtrusive $(function() { alert('The DOM is ready!'); });
  118. 118. Going unobtrusive jQuery(function($) { alert('The DOM is ready!'); });
  119. 119. Chaining • Most jQuery methods return another jQuery object - usually one representing the same collection. This means you can chain methods together: $('div.section').hide().addClass('gone');
  120. 120. Advanced chaining • Some methods return a different collection • You can call .end() to revert to the previous collection
  121. 121. Advanced chaining • Some methods return a different collection • You can call .end() to revert to the previous collection $('#intro').css('color', '#cccccc'). find('a').addClass('highlighted').end(). find('em').css('color', 'red').end()
  122. 122. Ajax • jQuery has excellent support for Ajax $('div#intro').load('/some/file.html'); • More advanced methods include: $.get(url, params, callback) $.post(url, params, callback) $.getJSON(url, params, callback) $.getScript(url, callback)
  123. 123. Animation • jQuery has built in effects: $('h1').hide('slow'); $('h1').slideDown('fast'); $('h1').fadeOut(2000); • You can chain them: $('h1').fadeOut(1000).slideDown()
  124. 124. Or roll your own... $(quot;#blockquot;).animate({ width: quot;+=60pxquot;, opacity: 0.4, fontSize: quot;3emquot;, borderWidth: quot;10pxquot; }, 1500);
  125. 125. Plugins • jQuery is extensible through plugins, which can add new methods to the jQuery object
  126. 126. Further reading • http://jquery.com/ • http://docs.jquery.com/ • http://visualjquery.com/ - API reference • http://simonwillison.net/tags/jquery/ • http://simonwillison.net/2007/Aug/15/jquery/ • http://24ways.org/2007/unobtrusively- mapping-microformats-with-jquery
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×