$30 off During Our Annual Pro Sale. View Details »

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. Introduction to
    Prototype
    Christophe Porteneuve
    The Ajax Experience · San Francisco, July 25 2007

    View Slide

  2. “Prototype,” uh?

    View Slide

  3. “Prototype,” uh?
    • Open-source JS framework

    View Slide

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

    View Slide

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

    View Slide

  6. “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...

    View Slide

  7. “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

    View Slide

  8. “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

    View Slide

  9. “Porteneuve,” uh?

    View Slide

  10. “Porteneuve,” uh?
    • 29, lives in Paris. Web work since 1995.

    View Slide

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

    View Slide

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

    View Slide

  13. “Porteneuve,” uh?
    • 29, lives in Paris. Web work since 1995.
    • CTO @ Ciblo.net
    • Prototype Core member
    • Rails & script.aculo.us contributor

    View Slide

  14. Prototype is people

    View Slide

  15. Prototype is people

    View Slide

  16. Prototype is people

    View Slide

  17. So you said, “intro...”

    View Slide

  18. So you said, “intro...”
    • We’ll take it easy: newbies, welcome!

    View Slide

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

    View Slide

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

    View Slide

  21. 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

    View Slide

  22. 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...

    View Slide

  23. 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...

    View Slide

  24. 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!

    View Slide

  25. JavaScript stuff you’d
    better know

    View Slide

  26. Everything is an object
    var speaker = { name: 'Christophe', age: 29, location: 'Paris' };

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. 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';

    View Slide

  32. 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'

    View Slide

  33. Arrays are not associative

    View Slide

  34. Arrays are not associative
    var data = ['mark', 'john', 'susie'];

    View Slide

  35. Arrays are not associative
    var data = ['mark', 'john', 'susie'];
    for (var name in data)
    alert(name);

    View Slide

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

    View Slide

  37. 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);

    View Slide

  38. 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'];

    View Slide

  39. 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]);

    View Slide

  40. 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);

    View Slide

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

    View Slide

  42. 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:

    View Slide

  43. 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:

    View Slide

  44. 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:

    View Slide

  45. The prototype property

    View Slide

  46. The prototype property
    • this.method = ... quickly get tedious

    View Slide

  47. The prototype property
    • this.method = ... quickly get tedious
    ‣ The constructors get overweight

    View Slide

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

    View Slide

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

    View Slide

  50. 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

    View Slide

  51. 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!

    View Slide

  52. 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

    View Slide

  53. The prototype property

    View Slide

  54. The prototype property
    function Person(name, age, location) {
    ...
    }

    View Slide

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

    View Slide

  56. 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 + ')';
    }

    View Slide

  57. 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');

    View Slide

  58. 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)'

    View Slide

  59. 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)'

    View Slide

  60. Extending JavaScript

    View Slide

  61. What could be improved?

    View Slide

  62. What could be improved?
    • So much stuff (no offense, Brendan!)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  68. What do we improve?

    View Slide

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

    View Slide

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

    View Slide

  71. 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

    View Slide

  72. 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...

    View Slide

  73. 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!

    View Slide

  74. 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 ;)

    View Slide

  75. Stretching your Strings

    View Slide

  76. Stretching your Strings
    // 29 new methods. Here are just a few...

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  80. 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!'

    View Slide

  81. 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 > 0 && x < 100'

    View Slide

  82. 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 > 0 && x < 100'
    'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}')

    View Slide

  83. 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 > 0 && x < 100'
    'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}')
    // 'xtEndengi JavScarpti'

    View Slide

  84. 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 > 0 && x < 100'
    'Extending JavaScript'.gsub(/([aeiouy])([^aeiouy]{2})/i, '#{2}#{1}')
    // 'xtEndengi JavScarpti'
    'the ajax experience'.gsub(/\w+/, function(match) {
    return match[0].capitalize();
    })

    View Slide

  85. 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 > 0 && x < 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'

    View Slide

  86. Arrays as über-collections

    View Slide

  87. Arrays as über-collections
    // 34 new methods, 19 of which from Enumerable (4 slides away)...

    View Slide

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

    View Slide

  89. 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

    View Slide

  90. 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

    View Slide

  91. 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]

    View Slide

  92. 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]

    View Slide

  93. 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]

    View Slide

  94. 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]

    View Slide

  95. 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() + '!';
    }

    View Slide

  96. 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!'

    View Slide

  97. 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']

    View Slide

  98. Numbers, the Ruby way

    View Slide

  99. Numbers, the Ruby way
    (5).times(function() {
    // Processed 5 times
    })

    View Slide

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

    View Slide

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

    View Slide

  102. 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

    View Slide

  103. 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

    View Slide

  104. A few Function tricks

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  108. 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);

    View Slide

  109. 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

    View Slide

  110. 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

    View Slide

  111. 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 + '!'); }

    View Slide

  112. 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

    View Slide

  113. 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();

    View Slide

  114. 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!

    View Slide

  115. New stuff you’ll love

    View Slide

  116. Enumerable

    View Slide

  117. Enumerable
    Mix it in your type and define _each:

    View Slide

  118. 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:

    View Slide

  119. 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:

    View Slide

  120. 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');

    View Slide

  121. 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);

    View Slide

  122. 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); })

    View Slide

  123. 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);
    });

    View Slide

  124. Enumerable (continued)

    View Slide

  125. Enumerable (continued)
    var tae = $w('The Ajax Experience');

    View Slide

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

    View Slide

  127. 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]

    View Slide

  128. 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]

    View Slide

  129. 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']

    View Slide

  130. 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']

    View Slide

  131. 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

    View Slide

  132. 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')

    View Slide

  133. 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']]

    View Slide

  134. 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]; })

    View Slide

  135. 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'

    View Slide

  136. Text interpolation

    View Slide

  137. Text interpolation
    var tpl = new Template(
    '#{name} is #{age} and lives in #{location}');

    View Slide

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

    View Slide

  139. 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'

    View Slide

  140. 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' };

    View Slide

  141. 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)

    View Slide

  142. 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'

    View Slide

  143. 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)

    View Slide

  144. 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'

    View Slide

  145. Ranges

    View Slide

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

    View Slide

  147. 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]

    View Slide

  148. 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; })

    View Slide

  149. 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

    View Slide

  150. 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'))

    View Slide

  151. 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']

    View Slide

  152. 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); })

    View Slide

  153. 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); })
    // ['*', '**', '***', '****']

    View Slide

  154. The DOM is fun again!

    View Slide

  155. What’s not fun about it?

    View Slide

  156. What’s not fun about it?
    • Is that a trick question?

    View Slide

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

    View Slide

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

    View Slide

  159. 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)

    View Slide

  160. 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)

    View Slide

  161. 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.)

    View Slide

  162. 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

    View Slide

  163. 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.

    View Slide

  164. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype

    View Slide

  165. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype


    View Slide

  166. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype




    View Slide

  167. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype






    View Slide

  168. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype








    View Slide

  169. DOM-related prototypes
    HTMLElement.
    prototype
    HTML*Element.
    prototype










    View Slide

  170. Element extension

    View Slide

  171. Element extension
    • Element.extend(yourElement)

    View Slide

  172. Element extension
    • Element.extend(yourElement)
    ‣ Adds all of Element.Methods (~60 methods)

    View Slide

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

    View Slide

  174. 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)

    View Slide

  175. 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

    View Slide

  176. The famous $ function

    View Slide

  177. The famous $ function
    • Most common need: grab an element by ID

    View Slide

  178. The famous $ function
    • Most common need: grab an element by ID
    • Runner-ups:

    View Slide

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

    View Slide

  180. 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

    View Slide

  181. 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 $(...)

    View Slide

  182. The famous $ function


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  183. The famous $ function
    $('article1')

    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  184. The famous $ function
    $('article1')
    //


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  185. The famous $ function
    $('article1')
    //
    $(firstDiv)


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  186. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  187. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  188. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')
    // [firstDiv, null, firstCommentDiv]


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  189. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')
    // [firstDiv, null, firstCommentDiv]
    $('article1', 'foobar', 'comment101').compact()


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  190. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')
    // [firstDiv, null, firstCommentDiv]
    $('article1', 'foobar', 'comment101').compact()
    // [firstDiv, firstCommentDiv]


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  191. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')
    // [firstDiv, null, firstCommentDiv]
    $('article1', 'foobar', 'comment101').compact()
    // [firstDiv, firstCommentDiv]
    $(firstDiv, 'article1', firstCommentDiv).uniq()


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  192. The famous $ function
    $('article1')
    //
    $(firstDiv)
    // firstDiv, with guaranteed extensions
    $('article1', 'foobar', 'comment101')
    // [firstDiv, null, firstCommentDiv]
    $('article1', 'foobar', 'comment101').compact()
    // [firstDiv, firstCommentDiv]
    $(firstDiv, 'article1', firstCommentDiv).uniq()
    // [firstDiv, firstCommentDiv]


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  193. $$ (The Almighty One)

    View Slide

  194. $$ (The Almighty One)
    • Relies on CSS3 selectors

    View Slide

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

    View Slide

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

    View Slide

  197. $$ (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...

    View Slide

  198. $$ (The Almighty One)


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  199. $$ (The Almighty One)
    $$('div')

    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  200. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  201. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  202. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  203. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  204. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')
    // Blah blah, Yada yada yada


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  205. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')
    // Blah blah, Yada yada yada
    $$('div.comments > div[id$="01"] > h3')


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  206. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')
    // Blah blah, Yada yada yada
    $$('div.comments > div[id$="01"] > h3')
    // h3, h3


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  207. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')
    // Blah blah, Yada yada yada
    $$('div.comments > div[id$="01"] > h3')
    // h3, h3
    $$('div:nth-child(2)')


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  208. $$ (The Almighty One)
    $$('div')
    // #article1, .comments, #comment101,
    // #article2, .comments, #comment201,
    // #comment202
    $$('div.comments')
    // .comments, .comments
    $$('h2 + p')
    // Blah blah, Yada yada yada
    $$('div.comments > div[id$="01"] > h3')
    // h3, h3
    $$('div:nth-child(2)')
    // #comment202


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  209. Traversing and aggregating


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  210. Traversing and aggregating
    $('article1').down() // Speaking!

    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  211. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  212. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  213. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  214. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  215. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  216. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  217. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()
    // div.comments, #article2, body


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  218. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()
    // div.comments, #article2, body
    $('article2').down().nextSiblings()


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  219. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()
    // div.comments, #article2, body
    $('article2').down().nextSiblings()
    // p, div.comments


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  220. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()
    // div.comments, #article2, body
    $('article2').down().nextSiblings()
    // p, div.comments
    $('article2').down('p').siblings()


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  221. Traversing and aggregating
    $('article1').down() // Speaking!
    $('comment101').up() // div.comments
    $('comment202').previous() // #comment201
    $('article1').next().down(1) // div.comments
    $('article2').down('h3', 1)
    // John @ 09:37am
    $('comment201').ancestors()
    // div.comments, #article2, body
    $('article2').down().nextSiblings()
    // p, div.comments
    $('article2').down('p').siblings()
    // h2, div.comments


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  222. Playing with visibility


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  223. Playing with visibility
    var hdr2 = $('article1').down('h2');

    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  224. Playing with visibility
    var hdr2 = $('article1').down('h2');
    hdr2.visible() // true


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  225. Playing with visibility
    var hdr2 = $('article1').down('h2');
    hdr2.visible() // true
    hdr2.hide() //


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  226. Playing with visibility
    var hdr2 = $('article1').down('h2');
    hdr2.visible() // true
    hdr2.hide() //
    hdr2.visible() // false


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  227. Playing with visibility
    var hdr2 = $('article1').down('h2');
    hdr2.visible() // true
    hdr2.hide() //
    hdr2.visible() // false
    hdr2.toggle() //


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  228. Playing with attributes
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  229. Playing with attributes
    var box = $('chkTOS');
    //
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  230. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  231. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  232. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  233. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    // checked="checked" .../>
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  234. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    // checked="checked" .../>
    box.readAttribute('checked')
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  235. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    // checked="checked" .../>
    box.readAttribute('checked')
    // 'checked'
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  236. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    // checked="checked" .../>
    box.readAttribute('checked')
    // 'checked'
    box.writeAttribute('checked', false)
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  237. Playing with attributes
    var box = $('chkTOS');
    //
    box.readAttribute('checked')
    // null
    box.writeAttribute('checked', true);
    // checked="checked" .../>
    box.readAttribute('checked')
    // 'checked'
    box.writeAttribute('checked', false)
    //
    action="/signup">
    ...

    id="chkTOS" name="tos"/>
    accesskey="T">I agree,
    wholeheartedly, to your
    wonderful terms of service.
    Love.

    ...

    View Slide

  238. Playing with style
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  239. Playing with style
    var hdr = $('article1').down('h2'); <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  240. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  241. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  242. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  243. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    //
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  244. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    //
    hdr.setStyle({ fontSize: '1.5em', true })
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  245. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    //
    hdr.setStyle({ fontSize: '1.5em', true })
    // Same, but slightly faster...
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  246. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    //
    hdr.setStyle({ fontSize: '1.5em', true })
    // Same, but slightly faster...
    hdr.setStyle({ fontSize: null, color: 'red' })
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  247. Playing with style
    var hdr = $('article1').down('h2');
    hdr.getStyle('font-size');
    // '1.2em'
    hdr.setStyle({ 'font-size': '1.5em' })
    //
    hdr.setStyle({ fontSize: '1.5em', true })
    // Same, but slightly faster...
    hdr.setStyle({ fontSize: null, color: 'red' })
    //
    <br/>h2 { font-size: 1.2em; }<br/>

    Speaking!
    Blah blah

    View Slide

  248. Dynamic contents!
    var hdr = $('article1').down('h2');
    hdr.update('TAE!');


    Speaking!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  249. Dynamic contents!
    var hdr = $('article1').down('h2');
    hdr.update('TAE!');


    TAE!
    Blah blah


    John @ 12:35pm
    yikes!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  250. Dynamic contents!
    var c1 = $('comment101');
    c1.insert('Yuck indeed!');


    TAE!
    Blah blah


    John @ 12:35pm
    yikes!
    Yuck indeed!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!


    ...

    View Slide

  251. Dynamic contents!
    var c1 = $('comment101');
    c1.insert('Yuck indeed!');
    c1.insert({ top: 'er, well...' });


    TAE!
    Blah blah


    er, well...
    John @ 12:35pm
    yikes!
    Yuck indeed!




    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!

    ...

    View Slide

  252. Dynamic contents!
    var c1 = $('comment101');
    c1.insert('Yuck indeed!');
    c1.insert({ top: 'er, well...' });
    c1.insert({ before: 'BEFORE',
    after: 'AFTER' });


    TAE!
    Blah blah

    BEFORE

    er, well...
    John @ 12:35pm
    yikes!
    Yuck indeed!

    AFTER



    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    ...

    View Slide

  253. Dynamic contents!
    var c1 = $('comment101');
    c1.insert('Yuck indeed!');
    c1.insert({ top: 'er, well...' });
    c1.insert({ before: 'BEFORE',
    after: 'AFTER' });
    c1.replace('--DELETED--');


    TAE!
    Blah blah

    BEFORE
    --DELETED--
    AFTER



    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!




    View Slide

  254. Explicit element creation
    var warning = new Element('img', {
    id: 'warning', src: '/i/warn.png',
    title: 'Watch out!'
    });
    $(document.body).insert({ top: warning });

    id="warning"
    title="Watch out!"/>

    TAE!
    Blah blah

    BEFORE
    --DELETED--
    AFTER



    Guess what?
    Yada yada yada


    Mark @ 09:20am
    cool!


    John @ 09:37am
    d'oh!

    ...

    View Slide

  255. Event handling

    View Slide

  256. The problems we face

    View Slide

  257. The problems we face
    • People keep using events the DOM0 way

    View Slide

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

    View Slide

  259. 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

    View Slide

  260. 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

    View Slide

  261. 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

    View Slide

  262. 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...

    View Slide

  263. 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

    View Slide

  264. Unifying the event code

    View Slide

  265. Unifying the event code
    • (De)registering handlers
    ‣ Event.observe, Event.stopObserving

    View Slide

  266. 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.

    View Slide

  267. 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...

    View Slide

  268. 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);

    View Slide

  269. 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);

    View Slide

  270. 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);

    View Slide

  271. 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);

    View Slide

  272. 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);

    View Slide

  273. Going AJAX

    View Slide

  274. X = XML?

    View Slide

  275. X = XML?
    • Yeah, but let’s just drop the XML garbage

    View Slide

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

    View Slide

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

    View Slide

  278. 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

    View Slide

  279. 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

    View Slide

  280. 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!

    View Slide

  281. Making an AJAX request

    View Slide

  282. Making an AJAX request
    new Ajax.Request('/articles/1', { method: 'get',
    onComplete: function(xhr) { /* process xhr.responseText */ }
    });

    View Slide

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

    View Slide

  284. 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...

    View Slide

  285. 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);
    }
    });

    View Slide

  286. Returning pure JavaScript?
    Leave this to me.
    new Ajax.Request('/persist', {
    parameters: $('form').serialize() });

    View Slide

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

    View Slide

  288. Returning pure JavaScript?
    Leave this to me.
    new Ajax.Request('/persist', {
    parameters: $('form').serialize() });
    $('indicator').hide();
    $('items').insert('...');
    $('item5').highlight.defer();
    ...
    eval(...)

    View Slide

  289. Submitting forms

    View Slide

  290. Submitting forms
    • At the core of AJAXifying a page...

    View Slide

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

    View Slide

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

    View Slide

  293. 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.

    View Slide

  294. 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

    View Slide

  295. Submitting forms

    View Slide

  296. Submitting forms
    • The HTML:

    View Slide

  297. Submitting forms
    • The HTML:





    View Slide

  298. Submitting forms
    • The HTML:





    • The JS:

    View Slide

  299. Submitting forms
    • The HTML:





    • The JS:
    var form = $('signinForm');
    form.observe('submit', function(e) {
    Event.stop(e);
    form.request();
    });

    View Slide

  300. AJAX returning markup

    View Slide

  301. AJAX returning markup
    • It’s everywhere!

    View Slide

  302. AJAX returning markup
    • It’s everywhere!
    ‣ Using the form’s method and action attributes

    View Slide

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

    View Slide

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

    View Slide

  305. 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, evaluation)<br/>

    View Slide

  306. 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, evaluation)<br/>‣ Can even be periodical (and slow down if no changes)<br/>

    View Slide

  307. AJAX returning markup

    View Slide

  308. AJAX returning markup
    new Ajax.Updater('container', '/url');

    View Slide

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

    View Slide

  310. 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() });

    View Slide

  311. 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() });

    View Slide

  312. 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() });

    View Slide

  313. Progressive enhancement:
    “Hijax”

    View Slide

  314. Progressive enhancement:
    “Hijax”
    • I’ll remind you that your markup should be

    View Slide

  315. Progressive enhancement:
    “Hijax”
    • I’ll remind you that your markup should be
    ‣ semantical

    View Slide

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

    View Slide

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

    View Slide

  318. 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.)

    View Slide

  319. 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

    View Slide

  320. 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

    View Slide

  321. But wait! There’s more!

    View Slide

  322. But wait! There’s more!
    • Next up: Advanced Prototype

    View Slide

  323. But wait! There’s more!
    • Next up: Advanced Prototype
    ‣ More Function-fu

    View Slide

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

    View Slide

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

    View Slide

  326. 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

    View Slide

  327. 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

    View Slide

  328. 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!

    View Slide

  329. Online resources

    View Slide

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

    View Slide

  331. 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

    View Slide

  332. 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

    View Slide

  333. Shameless plug

    View Slide

  334. Shameless plug

    View Slide

  335. Shameless plug
    • “The Bungee Book”

    View Slide

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

    View Slide

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

    View Slide

  338. 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

    View Slide

  339. 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!

    View Slide

  340. Q&A

    View Slide

  341. Q&A
    What Say You?

    View Slide