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

script.aculo.us

 script.aculo.us

Bacb1158b77a142d2cb8ae1f866c75f1?s=128

Christophe Porteneuve

July 25, 2007
Tweet

More Decks by Christophe Porteneuve

Other Decks in Technology

Transcript

  1. script.aculo.us Christophe Porteneuve The Ajax Experience · San Francisco, July

    25 2007
  2. This is an intro, yet...

  3. This is an intro, yet... • It’s better if you

    do know some Prototype
  4. This is an intro, yet... • It’s better if you

    do know some Prototype ‣ script.aculo.us relies heavily on it
  5. This is an intro, yet... • It’s better if you

    do know some Prototype ‣ script.aculo.us relies heavily on it ‣ If you just attended one of the Prototype sessions this morning, you should be fine
  6. This is an intro, yet... • It’s better if you

    do know some Prototype ‣ script.aculo.us relies heavily on it ‣ If you just attended one of the Prototype sessions this morning, you should be fine • As for script.aculo.us, we’ll skim the surface and showcast the features.
  7. Who am I?

  8. Who am I? • 29, lives in Paris. Web work

    since 1995
  9. Who am I? • 29, lives in Paris. Web work

    since 1995 • Prototype Core member
  10. Who am I? • 29, lives in Paris. Web work

    since 1995 • Prototype Core member • Rails & script.aculo.us contributor
  11. Who am I? • 29, lives in Paris. Web work

    since 1995 • Prototype Core member • Rails & script.aculo.us contributor • Prototype doc writer (prototypejs.org)
  12. Who am I? • 29, lives in Paris. Web work

    since 1995 • Prototype Core member • Rails & script.aculo.us contributor • Prototype doc writer (prototypejs.org) • Prototype & script.aculo.us book author
  13. Who am I? • 29, lives in Paris. Web work

    since 1995 • Prototype Core member • Rails & script.aculo.us contributor • Prototype doc writer (prototypejs.org) • Prototype & script.aculo.us book author • Top question batter on the Google Group
  14. What are we going to see?

  15. What are we going to see? • Visual effects

  16. What are we going to see? • Visual effects •

    Drag and drop, re-orderable elements
  17. What are we going to see? • Visual effects •

    Drag and drop, re-orderable elements • Autocompletion
  18. What are we going to see? • Visual effects •

    Drag and drop, re-orderable elements • Autocompletion • In-place editing
  19. What are we going to see? • Visual effects •

    Drag and drop, re-orderable elements • Autocompletion • In-place editing • Sliders
  20. What are we going to see? • Visual effects •

    Drag and drop, re-orderable elements • Autocompletion • In-place editing • Sliders • Concise DOM building
  21. Visual effects

  22. Overview

  23. Overview • No Flash, no SVG, just plain JS/CSS/DOM!

  24. Overview • No Flash, no SVG, just plain JS/CSS/DOM! •

    6 Core Effects, 18 Combined Effects
  25. Overview • No Flash, no SVG, just plain JS/CSS/DOM! •

    6 Core Effects, 18 Combined Effects • 9 “transitions” (control acceleration)
  26. Overview • No Flash, no SVG, just plain JS/CSS/DOM! •

    6 Core Effects, 18 Combined Effects • 9 “transitions” (control acceleration) • Fine-tune: 8 generic options, 7 callbacks
  27. Overview • No Flash, no SVG, just plain JS/CSS/DOM! •

    6 Core Effects, 18 Combined Effects • 9 “transitions” (control acceleration) • Fine-tune: 8 generic options, 7 callbacks • Queues to sync timelines
  28. Overview • No Flash, no SVG, just plain JS/CSS/DOM! •

    6 Core Effects, 18 Combined Effects • 9 “transitions” (control acceleration) • Fine-tune: 8 generic options, 7 callbacks • Queues to sync timelines • Custom effects easy to implement
  29. Triggering an effect

  30. Triggering an effect • new Effect.Name(element[, arg][, options])

  31. Triggering an effect • new Effect.Name(element[, arg][, options]) ‣ Mandatory

    argument sometimes (e.g. Scale)
  32. Triggering an effect • new Effect.Name(element[, arg][, options]) ‣ Mandatory

    argument sometimes (e.g. Scale) ‣ As usual, a hash of options. Many effects feature specific options in addition of the 8 generic ones.
  33. Triggering an effect • new Effect.Name(element[, arg][, options]) ‣ Mandatory

    argument sometimes (e.g. Scale) ‣ As usual, a hash of options. Many effects feature specific options in addition of the 8 generic ones. new Effect.Opacity('header', { to: 0.5 });
  34. Triggering an effect • new Effect.Name(element[, arg][, options]) ‣ Mandatory

    argument sometimes (e.g. Scale) ‣ As usual, a hash of options. Many effects feature specific options in addition of the 8 generic ones. new Effect.Opacity('header', { to: 0.5 }); new Effect.Highlight('notice', { duration: 2 });
  35. Triggering an effect • new Effect.Name(element[, arg][, options]) ‣ Mandatory

    argument sometimes (e.g. Scale) ‣ As usual, a hash of options. Many effects feature specific options in addition of the 8 generic ones. new Effect.Opacity('header', { to: 0.5 }); new Effect.Highlight('notice', { duration: 2 }); new Effect.Scale('mugshot', 200, { scaleFromCenter: true });
  36. Core effects

  37. Core effects • Opacity ‣ Alters an element’s opacity. Relies

    on the generic from/to options to define opacity.
  38. Core effects • Opacity ‣ Alters an element’s opacity. Relies

    on the generic from/to options to define opacity. • Move ‣ Absolute or relative movement
  39. Core effects • Opacity ‣ Alters an element’s opacity. Relies

    on the generic from/to options to define opacity. • Move ‣ Absolute or relative movement • Scale ‣ Resizing (impacting textual contents or not)
  40. Core effects

  41. Core effects • Highlight ‣ Cross-fading background color

  42. Core effects • Highlight ‣ Cross-fading background color • Morph

    ‣ Smoothly migrating any set of measurable CSS properties (colors, sizes) in sync!
  43. Core effects • Highlight ‣ Cross-fading background color • Morph

    ‣ Smoothly migrating any set of measurable CSS properties (colors, sizes) in sync! • Parallel ‣ Synchronized execution of multiple effects
  44. Generic options

  45. Generic options • When to start ‣ delay, queue

  46. Generic options • When to start ‣ delay, queue •

    How fast to go ‣ fps, sync, transition
  47. Generic options • When to start ‣ delay, queue •

    How fast to go ‣ fps, sync, transition • Cutting corners: where to start and stop ‣ from, to
  48. Core Effects demos

  49. Core Effects demos • Effect.Morph • Using custom queues •

    “Flash Stompers” ‣ Effect.multiple + Element.tagifyText • Creating a custom effect: Effect.Wave
  50. Combined effects

  51. Combined effects • Just like core, except you don’t need

    new
  52. Combined effects • Just like core, except you don’t need

    new • Many symmetrical ones: ‣ Appear/Fade, BlindDown/Up, SlideDown/Up ‣ Grow/Shrink
  53. Combined effects • Just like core, except you don’t need

    new • Many symmetrical ones: ‣ Appear/Fade, BlindDown/Up, SlideDown/Up ‣ Grow/Shrink • And funky ones to boot: ‣ DropOut, Puff, SwitchOff, Squish, Fold, Pulsate, Shake, Transform...
  54. Combined Effects demo • Let’s look at live examples of

    just about every combined effect...
  55. Drag and drop

  56. Overview

  57. Overview • Custom use / manual setup

  58. Overview • Custom use / manual setup ‣ Making an

    element draggable
  59. Overview • Custom use / manual setup ‣ Making an

    element draggable ‣ Setting up an element as a drop zone
  60. Overview • Custom use / manual setup ‣ Making an

    element draggable ‣ Setting up an element as a drop zone ‣ Controlling drag, restricting drops
  61. Overview • Custom use / manual setup ‣ Making an

    element draggable ‣ Setting up an element as a drop zone ‣ Controlling drag, restricting drops • Foremost use-case: re-orderable elements
  62. Making stuff draggable

  63. Making stuff draggable • new Draggable(element[, options])

  64. Making stuff draggable • new Draggable(element[, options]) • How easier

    can it get?!
  65. Making stuff draggable • new Draggable(element[, options]) • How easier

    can it get?! • Can be disabled by calling destroy() on the Draggable instance.
  66. Dragging, my way.

  67. Dragging, my way. • Reverting

  68. Dragging, my way. • Reverting • Movement restrictions (handle)

  69. Dragging, my way. • Reverting • Movement restrictions (handle) •

    Using specific handles to drag
  70. Dragging, my way. • Reverting • Movement restrictions (handle) •

    Using specific handles to drag • Staying within a scrolling container
  71. Dragging, my way. • Reverting • Movement restrictions (handle) •

    Using specific handles to drag • Staying within a scrolling container • Delayed triggering, dragging layer, ghosting...
  72. Dragging, my way. • Reverting • Movement restrictions (handle) •

    Using specific handles to drag • Staying within a scrolling container • Delayed triggering, dragging layer, ghosting... • Callbacks on start, drag step, drag release
  73. Dragging demo • A plump Tux wandering on a mini

    Chess board (now that’s an odd sight)
  74. Here’s your drop zone

  75. Here’s your drop zone • Droppables.add(element[, options])

  76. Here’s your drop zone • Droppables.add(element[, options]) • Droppables.remove(element)

  77. Here’s your drop zone • Droppables.add(element[, options]) • Droppables.remove(element) •

    Callbacks (dropped element & drop zone)
  78. Here’s your drop zone • Droppables.add(element[, options]) • Droppables.remove(element) •

    Callbacks (dropped element & drop zone)
  79. Here’s your drop zone • Droppables.add(element[, options]) • Droppables.remove(element) •

    Callbacks (dropped element & drop zone) • ...do we actually charge clients for this?!
  80. Not letting anybody in

  81. Not letting anybody in • Restricting on CSS class names

  82. Not letting anybody in • Restricting on CSS class names

    • Restricting on container of origin
  83. Drop demo • A shopping cart with a trash can

  84. Re-ordering lists... with your mouse

  85. Re-ordering lists... with your mouse • Sortable.create(container[, options])

  86. Re-ordering lists... with your mouse • Sortable.create(container[, options]) • Sortable.destroy(container)

  87. Re-ordering lists... with your mouse • Sortable.create(container[, options]) • Sortable.destroy(container)

  88. Re-ordering lists... with your mouse • Sortable.create(container[, options]) • Sortable.destroy(container)

  89. Re-ordering lists... with your mouse • Sortable.create(container[, options]) • Sortable.destroy(container)

    • Refund that client now, scoundrel!
  90. It doesn’t have to be lists...

  91. It doesn’t have to be lists... • It can be

    any container element, and any child elements
  92. It doesn’t have to be lists... • It can be

    any container element, and any child elements ‣ It doesn’t even have to be all the children
  93. It doesn’t have to be lists... • It can be

    any container element, and any child elements ‣ It doesn’t even have to be all the children ‣ It doesn’t have to be vertical
  94. It doesn’t have to be lists... • It can be

    any container element, and any child elements ‣ It doesn’t even have to be all the children ‣ It doesn’t have to be vertical ‣ You can even swap elements between containers!
  95. It doesn’t have to be lists... • It can be

    any container element, and any child elements ‣ It doesn’t even have to be all the children ‣ It doesn’t have to be vertical ‣ You can even swap elements between containers! • Two callbacks keep you posted on changes
  96. Re-ordering demos

  97. Re-ordering demos • A regular sorted list with callbacks and

    serialization of the updated order • An horizontal list (you gotta love CSS) • Re-ordering part of the <p>’s in a <div> • Playing with multiple lists
  98. Autocompletion

  99. Overview

  100. Overview • Assisted typing (e.g. Google Suggest) ‣ Terrific to

    reduce misspellings, duplicates... ‣ Helps accelerate the input process
  101. Overview • Assisted typing (e.g. Google Suggest) ‣ Terrific to

    reduce misspellings, duplicates... ‣ Helps accelerate the input process • Processes a ul/li list ‣ CSS can make it look like anything we want
  102. Overview • Assisted typing (e.g. Google Suggest) ‣ Terrific to

    reduce misspellings, duplicates... ‣ Helps accelerate the input process • Processes a ul/li list ‣ CSS can make it look like anything we want • Full keyboard+mouse operation
  103. Overview • Assisted typing (e.g. Google Suggest) ‣ Terrific to

    reduce misspellings, duplicates... ‣ Helps accelerate the input process • Processes a ul/li list ‣ CSS can make it look like anything we want • Full keyboard+mouse operation • Suggested items can be content-rich
  104. The basics

  105. The basics • new Ajax.Autocompleter(element, container, url[, options])

  106. The basics • new Ajax.Autocompleter(element, container, url[, options]) • A

    few CSS rules won’t hurt, too.
  107. The basics • new Ajax.Autocompleter(element, container, url[, options]) • A

    few CSS rules won’t hurt, too. • Plenty of cool options
  108. The basics • new Ajax.Autocompleter(element, container, url[, options]) • A

    few CSS rules won’t hurt, too. • Plenty of cool options ‣ autoSelect, minChars, frequency...
  109. The basics • new Ajax.Autocompleter(element, container, url[, options]) • A

    few CSS rules won’t hurt, too. • Plenty of cool options ‣ autoSelect, minChars, frequency... ‣ AJAX is 98% of use cases; can also be local...
  110. Dealing with rich contents

  111. Dealing with rich contents • Often suggesting texts alone is

    insufficient
  112. Dealing with rich contents • Often suggesting texts alone is

    insufficient • Example: company’s internal directory ‣ Just how many “John Smith” are at GE/BofA?
  113. Dealing with rich contents • Often suggesting texts alone is

    insufficient • Example: company’s internal directory ‣ Just how many “John Smith” are at GE/BofA? • Bringing up more info helps the user ‣ Dept. name, photo, dates, file sizes, whatever ‣ But completion should still extract our text
  114. Multiple-field completion

  115. Multiple-field completion • “John Smith, Corporate Accts” looks nice, but

    the server will hate it ‣ Why don’t you send it a nice person_id? ‣ You don’t want your server’s hatred...
  116. Multiple-field completion • “John Smith, Corporate Accts” looks nice, but

    the server will hate it ‣ Why don’t you send it a nice person_id? ‣ You don’t want your server’s hatred... • So we should hook up on the completion and grab more info from the selected entry ‣ Complete multiple fields, visible or hidden...
  117. Autocompletion demo

  118. Autocompletion demo • Consolidated demo ‣ AJAX completion based on

    installed Ruby libraries ‣ Rich contents ‣ Can complete multiple entries in the same field
  119. In-place editing

  120. Overview

  121. Overview • Makes any document fragment editable

  122. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place
  123. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place • Numerous options address most needs
  124. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place • Numerous options address most needs ‣ Working on an alternate text (i.e. not HTML)
  125. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place • Numerous options address most needs ‣ Working on an alternate text (i.e. not HTML) ‣ Customize editor controls
  126. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place • Numerous options address most needs ‣ Working on an alternate text (i.e. not HTML) ‣ Customize editor controls ‣ Offer a dropdown list instead of free typing
  127. Overview • Makes any document fragment editable ‣ Right there,

    right then: in place • Numerous options address most needs ‣ Working on an alternate text (i.e. not HTML) ‣ Customize editor controls ‣ Offer a dropdown list instead of free typing • Recently 100% rewritten: clean-slate code
  128. A simple editable fragment

  129. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options])

  130. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options]) ‣

    Uses an OK button and a Cancel link
  131. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options]) ‣

    Uses an OK button and a Cancel link ‣ Binds to Return and Esc
  132. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options]) ‣

    Uses an OK button and a Cancel link ‣ Binds to Return and Esc ‣ Uses a POST request
  133. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options]) ‣

    Uses an OK button and a Cancel link ‣ Binds to Return and Esc ‣ Uses a POST request ‣ Works over the native markup
  134. A simple editable fragment • new Ajax.InPlaceEditor(element, url[, options]) ‣

    Uses an OK button and a Cancel link ‣ Binds to Return and Esc ‣ Uses a POST request ‣ Works over the native markup ‣ Uses multiple-line editor only if needed
  135. Nips & tucks

  136. Nips & tucks • Tweak AJAX persistence ‣ paramName, callback,

    ajaxOptions, htmlResponse
  137. Nips & tucks • Tweak AJAX persistence ‣ paramName, callback,

    ajaxOptions, htmlResponse • Customize appearance ‣ TONS of options: controls, texts, CSS classes...
  138. Nips & tucks • Tweak AJAX persistence ‣ paramName, callback,

    ajaxOptions, htmlResponse • Customize appearance ‣ TONS of options: controls, texts, CSS classes... • Plenty of callbacks
  139. Working with an alternate textual form

  140. Working with an alternate textual form • Perhaps you’re storing

    these dynamic markups as something other than HTML
  141. Working with an alternate textual form • Perhaps you’re storing

    these dynamic markups as something other than HTML ‣ Textile? Markdown? Wiki? Something... darker?
  142. Working with an alternate textual form • Perhaps you’re storing

    these dynamic markups as something other than HTML ‣ Textile? Markdown? Wiki? Something... darker? • You’d want your user to edit in that format
  143. Working with an alternate textual form • Perhaps you’re storing

    these dynamic markups as something other than HTML ‣ Textile? Markdown? Wiki? Something... darker? • You’d want your user to edit in that format ‣ Load an alternate text when entering editing
  144. Working with an alternate textual form • Perhaps you’re storing

    these dynamic markups as something other than HTML ‣ Textile? Markdown? Wiki? Something... darker? • You’d want your user to edit in that format ‣ Load an alternate text when entering editing ‣ Respond to persistence with the matching markup, as usual
  145. Using a dropdown list

  146. Using a dropdown list • So your users can’t be

    trusted?
  147. Using a dropdown list • So your users can’t be

    trusted? • You’d like them to pick from a dropdown list (“combo”) instead...
  148. Using a dropdown list • So your users can’t be

    trusted? • You’d like them to pick from a dropdown list (“combo”) instead... • Just use Ajax.InPlaceCollectionEditor ‣ Collection can be local or AJAX-based
  149. In-place editing demos

  150. In-place editing demos • Simple editing with a few style

    options • Editing an alternate text representation • Using a collection-based editor
  151. Sliders

  152. Sliders in 30” (re-enacted by rabbits)

  153. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown)
  154. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track
  155. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track • Easy customization through CSS + options
  156. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track • Easy customization through CSS + options ‣ Orientation: vertical or horizontal
  157. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track • Easy customization through CSS + options ‣ Orientation: vertical or horizontal ‣ Restrict valid positions
  158. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track • Easy customization through CSS + options ‣ Orientation: vertical or horizontal ‣ Restrict valid positions ‣ Prevent handles from crossing each other
  159. Sliders in 30” (re-enacted by rabbits) • Replaces numerical input

    (free/dropdown) • One or more handles sliding on a track • Easy customization through CSS + options ‣ Orientation: vertical or horizontal ‣ Restrict valid positions ‣ Prevent handles from crossing each other ‣ Using handle pairs to define value ranges
  160. Slider demos

  161. Slider demos • Simple sliders ‣ Vertical & horizontal ‣

    Callbacks • Multiple-handle slider • 3 handles defining 2 ranges, no cross-over
  162. Concise DOM building

  163. Building DOM fragments “by hand” is booooring

  164. Building DOM fragments “by hand” is booooring • Yet sometimes

    update/insert won’t cut it ‣ Browser innerHTML (or equiv.) weirdness
  165. Building DOM fragments “by hand” is booooring • Yet sometimes

    update/insert won’t cut it ‣ Browser innerHTML (or equiv.) weirdness • Prototype has a nice new Element thing ‣ But one element at a time, no textual content
  166. Building DOM fragments “by hand” is booooring • Yet sometimes

    update/insert won’t cut it ‣ Browser innerHTML (or equiv.) weirdness • Prototype has a nice new Element thing ‣ But one element at a time, no textual content • So how do we manually build DOM fragments in a concise, expressive way?
  167. Builder.node

  168. Builder.node Builder.node('p')

  169. Builder.node Builder.node('p') // <p></p>

  170. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    })
  171. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p>
  172. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!')
  173. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p>
  174. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world')
  175. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p>
  176. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> Builder.node('div', [Builder.node('h2', 'Intro'), 'Hey'])
  177. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> Builder.node('div', [Builder.node('h2', 'Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div>
  178. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> Builder.node('div', [Builder.node('h2', 'Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div> Builder.node('div', { id: 'demo' }, ['Hey', Builder.node('h2', { className: 'regular' }, 'Intro')])
  179. Builder.node Builder.node('p') // <p></p> Builder.node('p', { id: 'demo', className: 'notice'

    }) // <p id="demo" class="notice"></p> Builder.node('p', 'Hello world!') // <p>Hello world!</p> Builder.node('p', { id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> Builder.node('div', [Builder.node('h2', 'Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div> Builder.node('div', { id: 'demo' }, ['Hey', Builder.node('h2', { className: 'regular' }, 'Intro')]) // <div id="demo">Hey<h2 class="regular">Intro</h2></div>
  180. Builder.dump: shortcuts!

  181. Builder.dump: shortcuts! Builder.dump();

  182. Builder.dump: shortcuts! Builder.dump(); P()

  183. Builder.dump: shortcuts! Builder.dump(); P() // <p></p>

  184. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' })
  185. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p>
  186. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!')
  187. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p>
  188. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world')
  189. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p>
  190. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> DIV('div', [H2('Intro'), 'Hey'])
  191. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> DIV('div', [H2('Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div>
  192. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> DIV('div', [H2('Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div> DIV({ id: 'demo' }, ['Hey', H2({ className: 'regular' }, 'Intro')])
  193. Builder.dump: shortcuts! Builder.dump(); P() // <p></p> P({ id: 'demo', className:

    'notice' }) // <p id="demo" class="notice"></p> P('Hello world!') // <p>Hello world!</p> P({ id: 'demo' }, 'Hello world') // <p id="demo">Hello world!</p> DIV('div', [H2('Intro'), 'Hey']) // <div><h2>Intro</h2>Hey</div> DIV({ id: 'demo' }, ['Hey', H2({ className: 'regular' }, 'Intro')]) // <div id="demo">Hey<h2 class="regular">Intro</h2></div>
  194. Builder demo • Interactive Builder code execution

  195. Online resources

  196. Online resources • The documentation sites ‣ http://prototypejs.org to understand

    the code ‣ http://script.aculo.us to download and read the Wiki (massive overhaul initiated)
  197. Online resources • The documentation sites ‣ http://prototypejs.org to understand

    the code ‣ http://script.aculo.us to download and read the Wiki (massive overhaul initiated) • The official list ‣ http://groups.google.com/rubyonrails-spinoffs
  198. Online resources • The documentation sites ‣ http://prototypejs.org to understand

    the code ‣ http://script.aculo.us to download and read the Wiki (massive overhaul initiated) • The official list ‣ http://groups.google.com/rubyonrails-spinoffs • IRC ‣ #scriptaculous on Freenode
  199. Shameless plug

  200. Shameless plug

  201. Shameless plug • “The Bungee Book”

  202. Shameless plug • “The Bungee Book” • Available already (as

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

    beta) from the Pragmatic Bookshelf ‣ http://books.pragprog.com/titles/cppsu/ • 95% content-complete already
  204. 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
  205. 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!
  206. Q&A

  207. Q&A What Say You?