Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Prototype.js

Introduction to Prototype.js

Christophe Porteneuve

July 25, 2007
Tweet

More Decks by Christophe Porteneuve

Other Decks in Technology

Transcript

  1. “Prototype,” uh? • Open-source JS framework • Extracted from real

    apps, real needs • Makes JS feel nicer (e.g. more expressive)
  2. “Prototype,” uh? • Open-source JS framework • Extracted from real

    apps, real needs • Makes JS feel nicer (e.g. more expressive) • NOT widget-oriented. More of a core...
  3. “Prototype,” uh? • Open-source JS framework • Extracted from real

    apps, real needs • Makes JS feel nicer (e.g. more expressive) • NOT widget-oriented. More of a core... • Actively maintained
  4. “Prototype,” uh? • Open-source JS framework • Extracted from real

    apps, real needs • Makes JS feel nicer (e.g. more expressive) • NOT widget-oriented. More of a core... • Actively maintained • Excellent online documentation
  5. “Porteneuve,” uh? • 29, lives in Paris. Web work since

    1995. • CTO @ Ciblo.net • Prototype Core member
  6. “Porteneuve,” uh? • 29, lives in Paris. Web work since

    1995. • CTO @ Ciblo.net • Prototype Core member • Rails & script.aculo.us contributor
  7. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway
  8. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway • What’s in this one?
  9. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway • What’s in this one? 1. These JS things you should know
  10. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway • What’s in this one? 1. These JS things you should know 2. How Prototype extends JavaScript...
  11. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway • What’s in this one? 1. These JS things you should know 2. How Prototype extends JavaScript... 3. How it puts the DOM on steroids...
  12. So you said, “intro...” • We’ll take it easy: newbies,

    welcome! • There’s an advanced session anyway • What’s in this one? 1. These JS things you should know 2. How Prototype extends JavaScript... 3. How it puts the DOM on steroids... 4. And how it makes AJAX a snap!
  13. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe'
  14. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe' person['name'] = 'Mislav';
  15. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe' person['name'] = 'Mislav'; person['name'] // 'Mislav'
  16. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe' person['name'] = 'Mislav'; person['name'] // 'Mislav' person.name // 'Mislav'
  17. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe' person['name'] = 'Mislav'; person['name'] // 'Mislav' person.name // 'Mislav' person.name = 'Tobie';
  18. Everything is an object var speaker = { name: 'Christophe',

    age: 29, location: 'Paris' }; person['name'] // 'Christophe' person['name'] = 'Mislav'; person['name'] // 'Mislav' person.name // 'Mislav' person.name = 'Tobie'; person.name // 'Tobie'
  19. Arrays are not associative • for...in iterates over all the

    properties! var data = ['mark', 'john', 'susie']; for (var name in data) alert(name); ✘
  20. Arrays are not associative • for...in iterates over all the

    properties! ‣ Includes all of Prototype’s extensions! var data = ['mark', 'john', 'susie']; for (var name in data) alert(name); ✘
  21. Arrays are not associative • for...in iterates over all the

    properties! ‣ Includes all of Prototype’s extensions! var data = ['mark', 'john', 'susie']; for (var name in data) alert(name); ✘ var data = ['mark', 'john', 'susie'];
  22. Arrays are not associative • for...in iterates over all the

    properties! ‣ Includes all of Prototype’s extensions! var data = ['mark', 'john', 'susie']; for (var name in data) alert(name); ✘ var data = ['mark', 'john', 'susie']; for (var index = 0, l = data.length; index < l; ++index) alert(data[index]);
  23. Arrays are not associative • for...in iterates over all the

    properties! ‣ Includes all of Prototype’s extensions! var data = ['mark', 'john', 'susie']; for (var name in data) alert(name); ✘ var data = ['mark', 'john', 'susie']; for (var index = 0, l = data.length; index < l; ++index) alert(data[index]); data.each(alert);
  24. Functions are objects, too. var personToString = function(person) { return

    person.name + ', ' + person.age + ' (' + person.location + ')'; } They’re values like any other:
  25. Functions are objects, too. var personToString = function(person) { return

    person.name + ', ' + person.age + ' (' + person.location + ')'; } var speaker = { name: 'Christophe', age: 29, location: 'Paris' }; speaker.toString = function() { return this.name + ', ' + this.age + ' (' + this.location + ')'; }; They’re values like any other: Same goes for methods:
  26. Functions as constructors function Person(name, age, location) { this.name =

    name; this.age = age; this.location = location; this.toString = function() { /*...*/ } } Just initialize your fields using this:
  27. Functions as constructors function Person(name, age, location) { this.name =

    name; this.age = age; this.location = location; this.toString = function() { /*...*/ } } var speaker = new Person('Christophe', 29, 'Paris'); speaker.name // 'Christophe' speaker.toString() // 'Christophe, 29 (Paris)' Just initialize your fields using this: And invoke using new:
  28. The prototype property • this.method = ... quickly get tedious

    ‣ The constructors get overweight ‣ It’s all actually singleton methods!
  29. The prototype property • this.method = ... quickly get tedious

    ‣ The constructors get overweight ‣ It’s all actually singleton methods! ‣ Save it for private/privileged methods
  30. The prototype property • this.method = ... quickly get tedious

    ‣ The constructors get overweight ‣ It’s all actually singleton methods! ‣ Save it for private/privileged methods • prototype: all instances rely on it
  31. The prototype property • this.method = ... quickly get tedious

    ‣ The constructors get overweight ‣ It’s all actually singleton methods! ‣ Save it for private/privileged methods • prototype: all instances rely on it ‣ Dynamic lookup: not just later instantiations!
  32. The prototype property • this.method = ... quickly get tedious

    ‣ The constructors get overweight ‣ It’s all actually singleton methods! ‣ Save it for private/privileged methods • prototype: all instances rely on it ‣ Dynamic lookup: not just later instantiations! ‣ The class’ repository of public methods
  33. The prototype property function Person(name, age, location) { ... }

    var sam = new Person('Sam', 23, 'Chicago');
  34. The prototype property function Person(name, age, location) { ... }

    var sam = new Person('Sam', 23, 'Chicago'); Person.prototype.toString = function() { return this.name + ', ' + this.age + ' (' + this.location + ')'; }
  35. The prototype property function Person(name, age, location) { ... }

    var sam = new Person('Sam', 23, 'Chicago'); Person.prototype.toString = function() { return this.name + ', ' + this.age + ' (' + this.location + ')'; } var tdd = new Person('Christophe', 29, 'Paris');
  36. The prototype property function Person(name, age, location) { ... }

    var sam = new Person('Sam', 23, 'Chicago'); Person.prototype.toString = function() { return this.name + ', ' + this.age + ' (' + this.location + ')'; } var tdd = new Person('Christophe', 29, 'Paris'); tdd.toString() // 'Christophe, 29 (Paris)'
  37. The prototype property function Person(name, age, location) { ... }

    var sam = new Person('Sam', 23, 'Chicago'); Person.prototype.toString = function() { return this.name + ', ' + this.age + ' (' + this.location + ')'; } var tdd = new Person('Christophe', 29, 'Paris'); tdd.toString() // 'Christophe, 29 (Paris)' sam.toString() // 'Sam, 23 (Chicago)'
  38. What could be improved? • So much stuff (no offense,

    Brendan!) • Arrays, collections in general, iterators...
  39. What could be improved? • So much stuff (no offense,

    Brendan!) • Arrays, collections in general, iterators... • Closures
  40. What could be improved? • So much stuff (no offense,

    Brendan!) • Arrays, collections in general, iterators... • Closures • Comprehensions
  41. What could be improved? • So much stuff (no offense,

    Brendan!) • Arrays, collections in general, iterators... • Closures • Comprehensions • Dynamic “inheritance,” method overriding
  42. What could be improved? • So much stuff (no offense,

    Brendan!) • Arrays, collections in general, iterators... • Closures • Comprehensions • Dynamic “inheritance,” method overriding • ...and more!
  43. What do we improve? • We beef up the basics:

    Array, String, Number, Function...
  44. What do we improve? • We beef up the basics:

    Array, String, Number, Function... • We unify event handling
  45. What do we improve? • We beef up the basics:

    Array, String, Number, Function... • We unify event handling • Sure, JS 1.7-2.0 introduce a ton of cool
  46. What do we improve? • We beef up the basics:

    Array, String, Number, Function... • We unify event handling • Sure, JS 1.7-2.0 introduce a ton of cool ‣ We try not to trump native stuff...
  47. What do we improve? • We beef up the basics:

    Array, String, Number, Function... • We unify event handling • Sure, JS 1.7-2.0 introduce a ton of cool ‣ We try not to trump native stuff... ‣ ...but not everybody has Firefox 3!
  48. What do we improve? • We beef up the basics:

    Array, String, Number, Function... • We unify event handling • Sure, JS 1.7-2.0 introduce a ton of cool ‣ We try not to trump native stuff... ‣ ...but not everybody has Firefox 3! ‣ ...and the syntax doesn’t always honor POLS ;)
  49. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true
  50. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false
  51. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true
  52. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!'
  53. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!' 'x > 0 && x < 100'.escapeHTML() // 'x &gt; 0 &amp;&amp; x &lt; 100'
  54. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!' 'x > 0 && x < 100'.escapeHTML() // 'x &gt; 0 &amp;&amp; x &lt; 100' 'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}')
  55. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!' 'x > 0 && x < 100'.escapeHTML() // 'x &gt; 0 &amp;&amp; x &lt; 100' 'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}') // 'xtEndengi JavScarpti'
  56. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!' 'x > 0 && x < 100'.escapeHTML() // 'x &gt; 0 &amp;&amp; x &lt; 100' 'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}') // 'xtEndengi JavScarpti' 'the ajax experience'.gsub(/\w+/, function(match) { return match[0].capitalize(); })
  57. Stretching your Strings // 29 new methods. Here are just

    a few... 'Prototype'.include('to') // true 'Prototype'.startsWith('Active') // false 'Prototype'.endsWith('type') // true 'Ho! '.times(3).strip() // 'Ho! Ho! Ho!' 'x > 0 && x < 100'.escapeHTML() // 'x &gt; 0 &amp;&amp; x &lt; 100' 'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}') // 'xtEndengi JavScarpti' 'the ajax experience'.gsub(/\w+/, function(match) { return match[0].capitalize(); }) // 'The Ajax Experience'
  58. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3
  59. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6
  60. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1
  61. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5]
  62. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3]
  63. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3] [1, 2, 3, 2, 1].without(1) // [2, 3, 2]
  64. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3] [1, 2, 3, 2, 1].without(1) // [2, 3, 2] [1, 2, 3, 3, 4, 2, 5].uniq() // [1, 2, 3, 4, 5]
  65. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3] [1, 2, 3, 2, 1].without(1) // [2, 3, 2] [1, 2, 3, 3, 4, 2, 5].uniq() // [1, 2, 3, 4, 5] function greet() { return 'Hey ' + $A(arguments).first() + '!'; }
  66. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3] [1, 2, 3, 2, 1].without(1) // [2, 3, 2] [1, 2, 3, 3, 4, 2, 5].uniq() // [1, 2, 3, 4, 5] function greet() { return 'Hey ' + $A(arguments).first() + '!'; } greet('Sam', 'Thomas', 'John') // 'Hey Sam!'
  67. Arrays as über-collections // 34 new methods, 19 of which

    from Enumerable (4 slides away)... [1, 2, 3].first() // 3 [4, 5, 6].last() // 6 [7, 8, 9].indexOf(8) // 1 [1, [2, 3], [4, [5], []]].flatten() // [1, 2, 3, 4, 5] [1, null, , 2, null, 3].compact() // [1, 2, 3] [1, 2, 3, 2, 1].without(1) // [2, 3, 2] [1, 2, 3, 3, 4, 2, 5].uniq() // [1, 2, 3, 4, 5] function greet() { return 'Hey ' + $A(arguments).first() + '!'; } greet('Sam', 'Thomas', 'John') // 'Hey Sam!' $w('eenie meenie minie moe') // ['eenie', 'meenie', 'minie', 'moe']
  68. Numbers, the Ruby way (5).times(function() { // Processed 5 times

    }) 'hello world!'.length.toPaddedString(3, 16) // '00c'
  69. Numbers, the Ruby way (5).times(function() { // Processed 5 times

    }) 'hello world!'.length.toPaddedString(3, 16) // '00c' (221).toColorPart() // 'dd' (2-digit hex)
  70. Numbers, the Ruby way (5).times(function() { // Processed 5 times

    }) 'hello world!'.length.toPaddedString(3, 16) // '00c' (221).toColorPart() // 'dd' (2-digit hex) Math.PI.ceil() // 4
  71. Numbers, the Ruby way (5).times(function() { // Processed 5 times

    }) 'hello world!'.length.toPaddedString(3, 16) // '00c' (221).toColorPart() // 'dd' (2-digit hex) Math.PI.ceil() // 4 (3 - 2 * 4).abs() // 5
  72. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; }
  73. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4);
  74. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5);
  75. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7
  76. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7 mul5(3) // 15
  77. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7 mul5(3) // 15 function greet(name) { alert('Hey ' + name + '!'); }
  78. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7 mul5(3) // 15 function greet(name) { alert('Hey ' + name + '!'); } greet.delay(1, 'Mark'); // will greet a second later
  79. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7 mul5(3) // 15 function greet(name) { alert('Hey ' + name + '!'); } greet.delay(1, 'Mark'); // will greet a second later updateDOMContents();
  80. A few Function tricks function add(x, y) { return x

    + y; } function mul(x, y) { return x * y; } var add4 = add.curry(4); var mul5 = mul.curry(5); add4(3) // 7 mul5(3) // 15 function greet(name) { alert('Hey ' + name + '!'); } greet.delay(1, 'Mark'); // will greet a second later updateDOMContents(); rebindListeners.defer(); // give a tiny moment to breathe, then go!
  81. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each:
  82. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each: That’s it! Let’s start with iterations:
  83. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each: That’s it! Let’s start with iterations: var tae = $w('The Ajax Experience');
  84. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each: That’s it! Let’s start with iterations: var tae = $w('The Ajax Experience'); tae.each(alert);
  85. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each: That’s it! Let’s start with iterations: var tae = $w('The Ajax Experience'); tae.each(alert); tae.each(function(word, index) { alert(index + ': ' + word); })
  86. Enumerable Object.extend(Array.prototype, Enumerable); Array.prototype._each = function(iterator) { for (var i

    = 0; i < this.length; i++) iterator(this[i]); }; Mix it in your type and define _each: That’s it! Let’s start with iterations: var tae = $w('The Ajax Experience'); tae.each(alert); tae.each(function(word, index) { alert(index + ': ' + word); }) tae.each(function(word, index) { if (index > 1) throw $break; alert(word); });
  87. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10]
  88. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10]
  89. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E']
  90. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc']
  91. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc'] tae.max(function(w) { return w.length; }) // 10
  92. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc'] tae.max(function(w) { return w.length; }) // 10 tae.zip(tae.pluck('length')).invoke('reverse')
  93. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc'] tae.max(function(w) { return w.length; }) // 10 tae.zip(tae.pluck('length')).invoke('reverse') // [[3, 'The'], [4, 'Ajax'], [10, 'Experience']]
  94. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc'] tae.max(function(w) { return w.length; }) // 10 tae.zip(tae.pluck('length')).invoke('reverse') // [[3, 'The'], [4, 'Ajax'], [10, 'Experience']] tae.inject('', function(acc, s) { return acc + s[0]; })
  95. Enumerable (continued) var tae = $w('The Ajax Experience'); tae.map(function(word) {

    return word[0]; }) // ['T', 'A', 'E'] tae.map(function(word) { return word.length; }) // [3, 4, 10] tae.pluck('length') // [3, 4, 10] tae.pluck(0) // ['T', 'A', 'E'] tae.invoke('gsub', /[aeiouy]+/i, '') // ['Th', 'jx', 'xprnc'] tae.max(function(w) { return w.length; }) // 10 tae.zip(tae.pluck('length')).invoke('reverse') // [[3, 'The'], [4, 'Ajax'], [10, 'Experience']] tae.inject('', function(acc, s) { return acc + s[0]; }) // 'TAE'
  96. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' })
  97. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris'
  98. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris' var mislav = { name: 'Mislav', age: 23, location: 'Zagreb' };
  99. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris' var mislav = { name: 'Mislav', age: 23, location: 'Zagreb' }; tpl.evaluate(mislav)
  100. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris' var mislav = { name: 'Mislav', age: 23, location: 'Zagreb' }; tpl.evaluate(mislav) // 'Mislav is 23 and lives in Zagreb'
  101. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris' var mislav = { name: 'Mislav', age: 23, location: 'Zagreb' }; tpl.evaluate(mislav) // 'Mislav is 23 and lives in Zagreb' // Pending commit to trunk: '#{name} is #{age} and lives in #{location}'.interpolate(mislav)
  102. Text interpolation var tpl = new Template( '#{name} is #{age}

    and lives in #{location}'); tpl.evaluate({ name: 'Christophe', age: 29, location: 'Paris' }) // 'Christophe is 29 and lives in Paris' var mislav = { name: 'Mislav', age: 23, location: 'Zagreb' }; tpl.evaluate(mislav) // 'Mislav is 23 and lives in Zagreb' // Pending commit to trunk: '#{name} is #{age} and lives in #{location}'.interpolate(mislav) // 'Mislav is 23 and lives in Zagreb'
  103. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  104. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; })
  105. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; }) // 120
  106. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; }) // 120 $A($R('a', 'm'))
  107. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; }) // 120 $A($R('a', 'm')) // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm']
  108. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; }) // 120 $A($R('a', 'm')) // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'] $R(1, 5, true).map(function(n) { return '*'.times(n); })
  109. Ranges new ObjectRange(1, 10).toArray() // [1, 2, 3, 4, 5,

    6, 7, 8, 9, 10] $A($R(1, 10)) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] $R(1, 15).inject(0, function(acc, n) { return acc + n; }) // 120 $A($R('a', 'm')) // ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'] $R(1, 5, true).map(function(n) { return '*'.times(n); }) // ['*', '**', '***', '****']
  110. What’s not fun about it? • Is that a trick

    question? ‣ Selecting elements for processing
  111. What’s not fun about it? • Is that a trick

    question? ‣ Selecting elements for processing ‣ Traversing it (don’t you hate indent nodes?)
  112. What’s not fun about it? • Is that a trick

    question? ‣ Selecting elements for processing ‣ Traversing it (don’t you hate indent nodes?) ‣ Performing common manipulations (e.g. class tweaking, visibility toggling)
  113. What’s not fun about it? • Is that a trick

    question? ‣ Selecting elements for processing ‣ Traversing it (don’t you hate indent nodes?) ‣ Performing common manipulations (e.g. class tweaking, visibility toggling) ‣ Cross-browser incompatibilities (e.g. attribute reading/writing, style tweaking)
  114. What’s not fun about it? • Is that a trick

    question? ‣ Selecting elements for processing ‣ Traversing it (don’t you hate indent nodes?) ‣ Performing common manipulations (e.g. class tweaking, visibility toggling) ‣ Cross-browser incompatibilities (e.g. attribute reading/writing, style tweaking) ‣ Content changes (update, replace, etc.)
  115. W3C DOM Level 2 HTML HTMLDocument HTMLElement HTMLHtmlElement HTMLHeadElement HTMLLinkElement

    HTMLTitleElement HTMLMetaElement HTMLBaseElement HTMLIsIndexElement HTMLStyleElement HTMLBodyElement HTMLFormElement HTMLSelectElement HTMLOptGroupElement HTMLOptionElement HTMLInputElement HTMLTextAreaElement HTMLButtonElement HTMLLabelElement HTMLFieldSetElement HTMLLegendElement HTMLUListElement HTMLOListElement HTMLDListElement HTMLDirectoryElement HTMLMenuElement HTMLLIElement HTMLDivElement HTMLParagraphElement HTMLHeadingElement HTMLQuoteElement HTMLPreElement HTMLBRElement HTMLBaseFontElement HTMLFontElement HTMLHRElement HTMLModElement HTMLAnchorElement HTMLImageElement HTMLObjectElement HTMLParamElement HTMLAppletElement HTMLMapElement HTMLAreaElement HTMLScriptElement HTMLTableElement HTMLTableCaptionElement HTMLTableColElement HTMLTableSectionElement HTMLTableRowElement HTMLTableCellElement HTMLFrameSetElement HTMLFrameElement HTMLIFrameElement
  116. W3C DOM Level 2 HTML HTMLDocument HTMLElement HTMLHtmlElement HTMLHeadElement HTMLLinkElement

    HTMLTitleElement HTMLMetaElement HTMLBaseElement HTMLIsIndexElement HTMLStyleElement HTMLBodyElement HTMLFormElement HTMLSelectElement HTMLOptGroupElement HTMLOptionElement HTMLInputElement HTMLTextAreaElement HTMLButtonElement HTMLLabelElement HTMLFieldSetElement HTMLLegendElement HTMLUListElement HTMLOListElement HTMLDListElement HTMLDirectoryElement HTMLMenuElement HTMLLIElement HTMLDivElement HTMLParagraphElement HTMLHeadingElement HTMLQuoteElement HTMLPreElement HTMLBRElement HTMLBaseFontElement HTMLFontElement HTMLHRElement HTMLModElement HTMLAnchorElement HTMLImageElement HTMLObjectElement HTMLParamElement HTMLAppletElement HTMLMapElement HTMLAreaElement HTMLScriptElement HTMLTableElement HTMLTableCaptionElement HTMLTableColElement HTMLTableSectionElement HTMLTableRowElement HTMLTableCellElement HTMLFrameSetElement HTMLFrameElement HTMLIFrameElement ✘ Yeah, right.
  117. Element extension • Element.extend(yourElement) ‣ Adds all of Element.Methods (~60

    methods) ‣ Take advantage of prototypes when available
  118. Element extension • Element.extend(yourElement) ‣ Adds all of Element.Methods (~60

    methods) ‣ Take advantage of prototypes when available ‣ Adds tag-specific extensions (e.g. form elements)
  119. Element extension • Element.extend(yourElement) ‣ Adds all of Element.Methods (~60

    methods) ‣ Take advantage of prototypes when available ‣ Adds tag-specific extensions (e.g. form elements) • Most of Prototype extends implicitly ‣ $, $$, all extended methods’ results
  120. The famous $ function • Most common need: grab an

    element by ID • Runner-ups: ‣ Grab many elements by their ID’s
  121. The famous $ function • Most common need: grab an

    element by ID • Runner-ups: ‣ Grab many elements by their ID’s ‣ Make sure an element is equipped with Prototype’s DOM extensions
  122. The famous $ function • Most common need: grab an

    element by ID • Runner-ups: ‣ Grab many elements by their ID’s ‣ Make sure an element is equipped with Prototype’s DOM extensions • Enter $(...)
  123. The famous $ function <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p>

    <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  124. The famous $ function $('article1') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah

    blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  125. The famous $ function $('article1') // <div id="article1"> <body> <div

    id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  126. The famous $ function $('article1') // <div id="article1"> $(firstDiv) <body>

    <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  127. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  128. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  129. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') // [firstDiv, null, firstCommentDiv] <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  130. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') // [firstDiv, null, firstCommentDiv] $('article1', 'foobar', 'comment101').compact() <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  131. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') // [firstDiv, null, firstCommentDiv] $('article1', 'foobar', 'comment101').compact() // [firstDiv, firstCommentDiv] <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  132. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') // [firstDiv, null, firstCommentDiv] $('article1', 'foobar', 'comment101').compact() // [firstDiv, firstCommentDiv] $(firstDiv, 'article1', firstCommentDiv).uniq() <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  133. The famous $ function $('article1') // <div id="article1"> $(firstDiv) //

    firstDiv, with guaranteed extensions $('article1', 'foobar', 'comment101') // [firstDiv, null, firstCommentDiv] $('article1', 'foobar', 'comment101').compact() // [firstDiv, firstCommentDiv] $(firstDiv, 'article1', firstCommentDiv).uniq() // [firstDiv, firstCommentDiv] <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  134. $$ (The Almighty One) • Relies on CSS3 selectors •

    Independent of your browser’s CSS3!
  135. $$ (The Almighty One) • Relies on CSS3 selectors •

    Independent of your browser’s CSS3! • Super-fast with DOM3 XPath
  136. $$ (The Almighty One) • Relies on CSS3 selectors •

    Independent of your browser’s CSS3! • Super-fast with DOM3 XPath • Very powerful attributes, classes, ID’s, hierarchy, position, tags/types, and more...
  137. $$ (The Almighty One) <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p>

    <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  138. $$ (The Almighty One) $$('div') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah

    blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  139. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  140. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  141. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  142. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  143. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') // <p>Blah blah</p>, <p>Yada yada yada</p> <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  144. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') // <p>Blah blah</p>, <p>Yada yada yada</p> $$('div.comments > div[id$="01"] > h3') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  145. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') // <p>Blah blah</p>, <p>Yada yada yada</p> $$('div.comments > div[id$="01"] > h3') // h3, h3 <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  146. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') // <p>Blah blah</p>, <p>Yada yada yada</p> $$('div.comments > div[id$="01"] > h3') // h3, h3 $$('div:nth-child(2)') <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  147. $$ (The Almighty One) $$('div') // #article1, .comments, #comment101, //

    #article2, .comments, #comment201, // #comment202 $$('div.comments') // .comments, .comments $$('h2 + p') // <p>Blah blah</p>, <p>Yada yada yada</p> $$('div.comments > div[id$="01"] > h3') // h3, h3 $$('div:nth-child(2)') // #comment202 <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  148. Traversing and aggregating <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div

    class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  149. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> <body> <div id="article1"> <h2>Speaking!</h2>

    <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  150. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments <body>

    <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  151. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  152. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  153. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  154. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  155. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  156. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() // div.comments, #article2, body <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  157. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() // div.comments, #article2, body $('article2').down().nextSiblings() <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  158. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() // div.comments, #article2, body $('article2').down().nextSiblings() // p, div.comments <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  159. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() // div.comments, #article2, body $('article2').down().nextSiblings() // p, div.comments $('article2').down('p').siblings() <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  160. Traversing and aggregating $('article1').down() // <h2>Speaking!</h2> $('comment101').up() // div.comments $('comment202').previous()

    // #comment201 $('article1').next().down(1) // div.comments $('article2').down('h3', 1) // <h3>John @ 09:37am</h3> $('comment201').ancestors() // div.comments, #article2, body $('article2').down().nextSiblings() // p, div.comments $('article2').down('p').siblings() // h2, div.comments <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  161. Playing with visibility <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div

    class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  162. Playing with visibility var hdr2 = $('article1').down('h2'); <body> <div id="article1">

    <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  163. Playing with visibility var hdr2 = $('article1').down('h2'); hdr2.visible() // true

    <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  164. Playing with visibility var hdr2 = $('article1').down('h2'); hdr2.visible() // true

    hdr2.hide() // <h2 style="display: none"> <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  165. Playing with visibility var hdr2 = $('article1').down('h2'); hdr2.visible() // true

    hdr2.hide() // <h2 style="display: none"> hdr2.visible() // false <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  166. Playing with visibility var hdr2 = $('article1').down('h2'); hdr2.visible() // true

    hdr2.hide() // <h2 style="display: none"> hdr2.visible() // false hdr2.toggle() // <h2> <body> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  167. Playing with attributes <form method="post" action="/signup"> ... <p> <input type="checkbox"

    id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  168. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  169. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  170. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  171. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  172. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); // <input type="checkbox" id="chkTOS" checked="checked" .../> <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  173. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); // <input type="checkbox" id="chkTOS" checked="checked" .../> box.readAttribute('checked') <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  174. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); // <input type="checkbox" id="chkTOS" checked="checked" .../> box.readAttribute('checked') // 'checked' <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  175. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); // <input type="checkbox" id="chkTOS" checked="checked" .../> box.readAttribute('checked') // 'checked' box.writeAttribute('checked', false) <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  176. Playing with attributes var box = $('chkTOS'); // <input type="checkbox"

    id="chkTOS" .../> box.readAttribute('checked') // null box.writeAttribute('checked', true); // <input type="checkbox" id="chkTOS" checked="checked" .../> box.readAttribute('checked') // 'checked' box.writeAttribute('checked', false) // <input type="checkbox" id="chkTOS" .../> <form method="post" action="/signup"> ... <p> <input type="checkbox" id="chkTOS" name="tos"/> <label for="chkTOS" accesskey="T">I agree, wholeheartedly, to your wonderful terms of service. Love.</label> </p> ... </form>
  177. Playing with style <style type="text/css"> h2 { font-size: 1.2em; }

    </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  178. Playing with style var hdr = $('article1').down('h2'); <style type="text/css"> h2

    { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  179. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); <style type="text/css">

    h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  180. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  181. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  182. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) // <h2 style="font-size: 1.5em"> <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  183. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) // <h2 style="font-size: 1.5em"> hdr.setStyle({ fontSize: '1.5em', true }) <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  184. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) // <h2 style="font-size: 1.5em"> hdr.setStyle({ fontSize: '1.5em', true }) // Same, but slightly faster... <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  185. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) // <h2 style="font-size: 1.5em"> hdr.setStyle({ fontSize: '1.5em', true }) // Same, but slightly faster... hdr.setStyle({ fontSize: null, color: 'red' }) <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  186. Playing with style var hdr = $('article1').down('h2'); hdr.getStyle('font-size'); // '1.2em'

    hdr.setStyle({ 'font-size': '1.5em' }) // <h2 style="font-size: 1.5em"> hdr.setStyle({ fontSize: '1.5em', true }) // Same, but slightly faster... hdr.setStyle({ fontSize: null, color: 'red' }) // <h2 style="color: red"> <style type="text/css"> h2 { font-size: 1.2em; } </style> <div id="article1"> <h2>Speaking!</h2> <p>Blah blah</p> </div>
  187. Dynamic contents! var hdr = $('article1').down('h2'); hdr.update('<span>TAE!</span>'); <body> <div id="article1">

    <h2>Speaking!</h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  188. Dynamic contents! var hdr = $('article1').down('h2'); hdr.update('<span>TAE!</span>'); <body> <div id="article1">

    <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  189. Dynamic contents! var c1 = $('comment101'); c1.insert('<p>Yuck indeed!</p>'); <body> <div

    id="article1"> <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <h3>John @ 12:35pm</h3> <p>yikes!</p> <p>Yuck indeed!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> ...
  190. Dynamic contents! var c1 = $('comment101'); c1.insert('<p>Yuck indeed!</p>'); c1.insert({ top:

    '<p>er, well...</p>' }); <body> <div id="article1"> <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> <div id="comment101"> <p>er, well...</p> <h3>John @ 12:35pm</h3> <p>yikes!</p> <p>Yuck indeed!</p> </div> </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> ...
  191. Dynamic contents! var c1 = $('comment101'); c1.insert('<p>Yuck indeed!</p>'); c1.insert({ top:

    '<p>er, well...</p>' }); c1.insert({ before: 'BEFORE', after: 'AFTER' }); <body> <div id="article1"> <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> BEFORE <div id="comment101"> <p>er, well...</p> <h3>John @ 12:35pm</h3> <p>yikes!</p> <p>Yuck indeed!</p> </div> AFTER </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> ...
  192. Dynamic contents! var c1 = $('comment101'); c1.insert('<p>Yuck indeed!</p>'); c1.insert({ top:

    '<p>er, well...</p>' }); c1.insert({ before: 'BEFORE', after: 'AFTER' }); c1.replace('<p>--DELETED--</p>'); <body> <div id="article1"> <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> BEFORE <p>--DELETED--</p> AFTER </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> </div> </div> </body>
  193. Explicit element creation var warning = new Element('img', { id:

    'warning', src: '/i/warn.png', title: 'Watch out!' }); $(document.body).insert({ top: warning }); <body> <img src="/i/warn.png" id="warning" title="Watch out!"/> <div id="article1"> <h2><span>TAE!</span></h2> <p>Blah blah</p> <div class="comments"> BEFORE <p>--DELETED--</p> AFTER </div> </div> <div id="article2"> <h2>Guess what?</h2> <p>Yada yada yada</p> <div class="comments"> <div id="comment201"> <h3>Mark @ 09:20am</h3> <p>cool!</p> </div> <div id="comment202"> <h3>John @ 09:37am</h3> <p>d'oh!</p> </div> ...
  194. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE
  195. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE • IE vs. The Rest Of The World
  196. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE • IE vs. The Rest Of The World ‣ (De)registering event handlers
  197. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE • IE vs. The Rest Of The World ‣ (De)registering event handlers ‣ Getting / manipulating the event object
  198. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE • IE vs. The Rest Of The World ‣ (De)registering event handlers ‣ Getting / manipulating the event object ‣ Bubbling & capturing, key events, key codes...
  199. The problems we face • People keep using events the

    DOM0 way ‣ Inline handlers skip the event object in IE • IE vs. The Rest Of The World ‣ (De)registering event handlers ‣ Getting / manipulating the event object ‣ Bubbling & capturing, key events, key codes... • Not just IE: Safari/Opera b0rk sometimes
  200. Unifying the event code • (De)registering handlers ‣ Event.observe, Event.stopObserving

    • Manipulating the event object ‣ Event.pointer(X|Y), Event.element, Event.stop, Event.KEY_xxx, etc.
  201. Unifying the event code • (De)registering handlers ‣ Event.observe, Event.stopObserving

    • Manipulating the event object ‣ Event.pointer(X|Y), Event.element, Event.stop, Event.KEY_xxx, etc. • Working around the tweaks ‣ e.g. keypress/keydown in Safari, submit...
  202. What it looks like function bindPopupLinks() { $$('a.popup').invoke('observe', 'click', handlePopupLinkClick);

    } function handlePopupLinkClick(e) { Event.stop(e); var lnk = Event.findElement(e, 'a'); var opts = 'width=500,height=400...'; window.open(lnk.href, 'wndPopupLink', opts); } // Prototype 1.6 should emulate DOMContentLoaded properly... Event.observe(window, 'DOMContentLoaded', bindPopupLinks);
  203. What it looks like function bindPopupLinks() { $$('a.popup').invoke('observe', 'click', handlePopupLinkClick);

    } function handlePopupLinkClick(e) { Event.stop(e); var lnk = Event.findElement(e, 'a'); var opts = 'width=500,height=400...'; window.open(lnk.href, 'wndPopupLink', opts); } // Prototype 1.6 should emulate DOMContentLoaded properly... Event.observe(window, 'DOMContentLoaded', bindPopupLinks);
  204. What it looks like function bindPopupLinks() { $$('a.popup').invoke('observe', 'click', handlePopupLinkClick);

    } function handlePopupLinkClick(e) { Event.stop(e); var lnk = Event.findElement(e, 'a'); var opts = 'width=500,height=400...'; window.open(lnk.href, 'wndPopupLink', opts); } // Prototype 1.6 should emulate DOMContentLoaded properly... Event.observe(window, 'DOMContentLoaded', bindPopupLinks);
  205. What it looks like function bindPopupLinks() { $$('a.popup').invoke('observe', 'click', handlePopupLinkClick);

    } function handlePopupLinkClick(e) { Event.stop(e); var lnk = Event.findElement(e, 'a'); var opts = 'width=500,height=400...'; window.open(lnk.href, 'wndPopupLink', opts); } // Prototype 1.6 should emulate DOMContentLoaded properly... Event.observe(window, 'DOMContentLoaded', bindPopupLinks);
  206. What it looks like function bindPopupLinks() { $$('a.popup').invoke('observe', 'click', handlePopupLinkClick);

    } function handlePopupLinkClick(e) { Event.stop(e); var lnk = Event.findElement(e, 'a'); var opts = 'width=500,height=400...'; window.open(lnk.href, 'wndPopupLink', opts); } // Prototype 1.6 should emulate DOMContentLoaded properly... Event.observe(window, 'DOMContentLoaded', bindPopupLinks);
  207. X = XML? • Yeah, but let’s just drop the

    XML garbage ‣ What’s your cross to bear, SOAP with JS?
  208. X = XML? • Yeah, but let’s just drop the

    XML garbage ‣ What’s your cross to bear, SOAP with JS? • X = XHTML
  209. X = XML? • Yeah, but let’s just drop the

    XML garbage ‣ What’s your cross to bear, SOAP with JS? • X = XHTML ‣ I mean, we all send back XHTML anyway
  210. X = XML? • Yeah, but let’s just drop the

    XML garbage ‣ What’s your cross to bear, SOAP with JS? • X = XHTML ‣ I mean, we all send back XHTML anyway ‣ Unless it’s JSON or plain JS to be eval’d
  211. X = XML? • Yeah, but let’s just drop the

    XML garbage ‣ What’s your cross to bear, SOAP with JS? • X = XHTML ‣ I mean, we all send back XHTML anyway ‣ Unless it’s JSON or plain JS to be eval’d ‣ We’re all doing AHAH, knowing it or not!
  212. Making an AJAX request new Ajax.Request('/articles/1', { method: 'get', onComplete:

    function(xhr) { /* process xhr.responseText */ } }); • Plenty of options!
  213. Making an AJAX request new Ajax.Request('/articles/1', { method: 'get', onComplete:

    function(xhr) { /* process xhr.responseText */ } }); • Plenty of options! ‣ Method, callbacks, parameters, headers, encoding...
  214. Making an AJAX request new Ajax.Request('/articles/1', { method: 'get', onComplete:

    function(xhr) { /* process xhr.responseText */ } }); • Plenty of options! ‣ Method, callbacks, parameters, headers, encoding... new Ajax.Request('/signin', { parameters: { login: 'john', password: 'foobar' }, requestHeaders: { 'X-Auth-Mode': 'XHR' }, onFailure: function(xhr) { alert(xhr.responseText); }, onComplete: function(xhr) { $('loginForm').update(xhr.responseText); } });
  215. Returning pure JavaScript? Leave this to me. new Ajax.Request('/persist', {

    parameters: $('form').serialize() }); $('indicator').hide(); $('items').insert('<li id=”item5”>...'); $('item5').highlight.defer(); ...
  216. Returning pure JavaScript? Leave this to me. new Ajax.Request('/persist', {

    parameters: $('form').serialize() }); $('indicator').hide(); $('items').insert('<li id=”item5”>...'); $('item5').highlight.defer(); ... eval(...)
  217. Submitting forms • At the core of AJAXifying a page...

    ‣ Using the form’s method and action attributes
  218. Submitting forms • At the core of AJAXifying a page...

    ‣ Using the form’s method and action attributes ‣ Serializing it according to HTML spec
  219. Submitting forms • At the core of AJAXifying a page...

    ‣ Using the form’s method and action attributes ‣ Serializing it according to HTML spec ‣ Returning JS? You’re done! Otherwise use onComplete.
  220. Submitting forms • At the core of AJAXifying a page...

    ‣ Using the form’s method and action attributes ‣ Serializing it according to HTML spec ‣ Returning JS? You’re done! Otherwise use onComplete. • In phase with accessibility / unobstrusive JS
  221. Submitting forms • The HTML: <form id="signinForm" method="post" action="/signin"> <p><input

    type="text" name="login" value="john"/></p> <p><input type="password" name="password" value="foobar"/></p> <p><input type="submit" value="Sign in!"/></p> </form>
  222. Submitting forms • The HTML: <form id="signinForm" method="post" action="/signin"> <p><input

    type="text" name="login" value="john"/></p> <p><input type="password" name="password" value="foobar"/></p> <p><input type="submit" value="Sign in!"/></p> </form> • The JS:
  223. Submitting forms • The HTML: <form id="signinForm" method="post" action="/signin"> <p><input

    type="text" name="login" value="john"/></p> <p><input type="password" name="password" value="foobar"/></p> <p><input type="submit" value="Sign in!"/></p> </form> • The JS: var form = $('signinForm'); form.observe('submit', function(e) { Event.stop(e); form.request(); });
  224. AJAX returning markup • It’s everywhere! ‣ Using the form’s

    method and action attributes • In essence: container.update(xhr.responseText)
  225. AJAX returning markup • It’s everywhere! ‣ Using the form’s

    method and action attributes • In essence: container.update(xhr.responseText) • Automagically done!
  226. AJAX returning markup • It’s everywhere! ‣ Using the form’s

    method and action attributes • In essence: container.update(xhr.responseText) • Automagically done! ‣ Quite a few cool options (success/failure branching, inserting instead of updating, <script> evaluation)
  227. AJAX returning markup • It’s everywhere! ‣ Using the form’s

    method and action attributes • In essence: container.update(xhr.responseText) • Automagically done! ‣ Quite a few cool options (success/failure branching, inserting instead of updating, <script> evaluation) ‣ Can even be periodical (and slow down if no changes)
  228. AJAX returning markup new Ajax.Updater('container', '/url'); new Ajax.Updater('todo1', '/todos/1/items', {

    insertion: 'bottom', parameters: $('itemForm').serialize() }); new Ajax.Updater('todo1', '/todos/1', { method: 'get', evalScripts: true, parameters: $('todoForm').serialize() });
  229. AJAX returning markup new Ajax.Updater('container', '/url'); new Ajax.Updater('todo1', '/todos/1/items', {

    insertion: 'bottom', parameters: $('itemForm').serialize() }); new Ajax.Updater('todo1', '/todos/1', { method: 'get', evalScripts: true, parameters: $('todoForm').serialize() }); new Ajax.Updater({ success: 'todo1', failure: 'errors' }, '/todos/1', { parameters: $('todoForm').serialize() });
  230. AJAX returning markup new Ajax.Updater('container', '/url'); new Ajax.Updater('todo1', '/todos/1/items', {

    insertion: 'bottom', parameters: $('itemForm').serialize() }); new Ajax.Updater('todo1', '/todos/1', { method: 'get', evalScripts: true, parameters: $('todoForm').serialize() }); new Ajax.Updater({ success: 'todo1', failure: 'errors' }, '/todos/1', { parameters: $('todoForm').serialize() }); new Ajax.Updater({ success: 'todo1' }, '/todos/1', { parameters: $('todoForm').serialize() });
  231. Progressive enhancement: “Hijax” • I’ll remind you that your markup

    should be ‣ semantical ‣ self-sufficient (works w/o JS)
  232. Progressive enhancement: “Hijax” • I’ll remind you that your markup

    should be ‣ semantical ‣ self-sufficient (works w/o JS) • The recipe is simple:
  233. Progressive enhancement: “Hijax” • I’ll remind you that your markup

    should be ‣ semantical ‣ self-sufficient (works w/o JS) • The recipe is simple: ‣ Plan for AJAX early (controllers/views, etc.)
  234. Progressive enhancement: “Hijax” • I’ll remind you that your markup

    should be ‣ semantical ‣ self-sufficient (works w/o JS) • The recipe is simple: ‣ Plan for AJAX early (controllers/views, etc.) ‣ Implement it when the page works already
  235. Progressive enhancement: “Hijax” • I’ll remind you that your markup

    should be ‣ semantical ‣ self-sufficient (works w/o JS) • The recipe is simple: ‣ Plan for AJAX early (controllers/views, etc.) ‣ Implement it when the page works already ‣ Use unobstrusive JavaScript
  236. But wait! There’s more! • Next up: Advanced Prototype ‣

    More Function-fu ‣ Best coding practices (e.g. on Enumerable)
  237. But wait! There’s more! • Next up: Advanced Prototype ‣

    More Function-fu ‣ Best coding practices (e.g. on Enumerable) ‣ JSON love
  238. But wait! There’s more! • Next up: Advanced Prototype ‣

    More Function-fu ‣ Best coding practices (e.g. on Enumerable) ‣ JSON love ‣ Whipping up your own DOM extensions
  239. But wait! There’s more! • Next up: Advanced Prototype ‣

    More Function-fu ‣ Best coding practices (e.g. on Enumerable) ‣ JSON love ‣ Whipping up your own DOM extensions ‣ Creating your own classes
  240. But wait! There’s more! • Next up: Advanced Prototype ‣

    More Function-fu ‣ Best coding practices (e.g. on Enumerable) ‣ JSON love ‣ Whipping up your own DOM extensions ‣ Creating your own classes ‣ Sneak peek at Prototype 1.6, and more!
  241. Online resources • The excellent documentation site ‣ http://prototypejs.org ‣

    API reference, tutorials, downloads, blog... ‣ Soon: 3rd-party libs roster
  242. Online resources • The excellent documentation site ‣ http://prototypejs.org ‣

    API reference, tutorials, downloads, blog... ‣ Soon: 3rd-party libs roster • The official list (does script.aculo.us too) ‣ http://groups.google.com/rubyonrails-spinoffs
  243. Online resources • The excellent documentation site ‣ http://prototypejs.org ‣

    API reference, tutorials, downloads, blog... ‣ Soon: 3rd-party libs roster • The official list (does script.aculo.us too) ‣ http://groups.google.com/rubyonrails-spinoffs • IRC ‣ #prototype on Freenode
  244. Shameless plug • “The Bungee Book” • Available already (as

    beta) from the Pragmatic Bookshelf ‣ http://books.pragprog.com/titles/cppsu/
  245. Shameless plug • “The Bungee Book” • Available already (as

    beta) from the Pragmatic Bookshelf ‣ http://books.pragprog.com/titles/cppsu/ • 95% content-complete already
  246. Shameless plug • “The Bungee Book” • Available already (as

    beta) from the Pragmatic Bookshelf ‣ http://books.pragprog.com/titles/cppsu/ • 95% content-complete already • Up-to-date on the latest stuff
  247. Shameless plug • “The Bungee Book” • Available already (as

    beta) from the Pragmatic Bookshelf ‣ http://books.pragprog.com/titles/cppsu/ • 95% content-complete already • Up-to-date on the latest stuff • Pre-order the paper book too!
  248. Q&A