What’s up with Prototype and
script.aculo.us? (Shiny things in Spinoffsland)

Christophe Porteneuve
CTO, Ciblo.net + Proto...
Did you guys catch our Prototype
Developer Day?

• That was on Monday morning
 • Bringing the community together
 • Discus...
What we’re going to see

• Prototype 1.6 → 1.6.0.3
 • Custom events
 • Class system
 • Other various improvements
• Where ...
Prototype 1.6
Prototype 1.6

• “Hey, that was almost a year ago!”
 • Yeah, but never discussed at TAE yet (plus, 1.6.0.3 now…)
 • And a ...
Custom events: overview

• Events our own JS code triggers
• Attached to DOM nodes
• Bubble like regular DOM events
• Publ...
Custom events: naming and availability

• How do we tell a custom event from a native one?
 • The custom event’s name must...
Custom events: “creating” them

• Just observe one somewhere in your code

initComputation: function() {
  var target = th...
Custom events: triggering them

• Simply call fire on the relevant DOM element



new Field.Observer('edtReqTaxRate', 0.5,...
Custom events: the memo property

initComputation: function() {
  var target = this.element.down('.computed'), that = this...
Custom events: already much in style

• Especially by UI-oriented third-party libraries
 • Lets them create a full communi...
dom:loaded

• Our first “standard” custom event
• Triggers right after DOM load
• So just forget
 Event.observe(window, 'l...
A note about stopObserving

• You can make partial calls now
• Omit the handler
 myEditor.stopObserving('change');

 • All...
More Event goodness

• Guaranteed even methods and properties
 • relatedTarget, pageX, pageY
 • stopPropagation(), prevent...
A note on event binding

• Pre-1.6, handlers were “unbound” by default
 • Unless you had bound them explicitly, they’d end...
New class system

• The idea: ease up traditional OOP constructs and
 behaviors
 • Inheritance
 • Mix-ins
 • Method overri...
Ye Olde Class

var MyClass = Class.create({
  initialize: function(…) {
                                  • Key issues:
  ...
The new class syntax

var MyClass = Class.create([parentClass, ][mixIns…, ]{
   [initialize: function(…) { … },]
   public...
Inheritance becomes a breeze

var XMLParser = Class.create({
  initialize: function(source) { … },
  …
});

var XHTMLParse...
Free stuff you get

• Every instance has a constructor
• Every class has a superclass and subclasses
XMLParser.superclass ...
Mixing in modules

• A module is just a bag of properties/methods
• You can mix as many of those as you want at class
 cre...
Class methods

• These are just methods on the Class object itself,
 so we can resort to good ol’ Object.extend.
var MyGen...
Adding methods post-declaration

• Every class has a addMethods method that mixes
 anything module-like in.
• It’s actuall...
Accessing overridden methods

• Insert a $super first argument. That’s it.
var XMLParser = Class.create({
  initialize: fu...
Function-fu

• Prototype 1.6 introduced a lot of new methods on
 function so you can reduce custom anonymous
 wrappers and...
Spicying up your code with curry

• You know how you always use bind(null,…) just
 because you need partial application?
 ...
curry vs. bind

• You should use bind when…
 • You actually need to bind (set the semantics of this)
 • It doesn’t matter ...
Deferring execution: delay and defer

• Schedule execution of a snippet of JS for later
 • Either a specific time later
 •...
Classical defer use-case

• You just added to the DOM
• You need to manipulate the added fragment now
 • Attach event list...
Classical defer use-case
 function addAndBindForm(formMarkup) {
   $('formsContainer').insert(formMarkup);
   $('formsCont...
Going AOP / Decorator with wrap

• Replacing a method with an augmented version of
 it, which means you get a reference to...
argumentNames

• Array of argument names for a given function
• Hackish: relies on functions’ toString() capability
 • Won...
Ajax.Response

• Encapsulates the whole response you get
 • Headers + body
• Extracts relevant-type contents
 • responseTe...
Before/after 1.6 for response analysis

           Before 1.6                          Since 1.6
   callback(requester, he...
Content insertion

• Element.insert/wrap
 • insert now takes either a single element (bottom insertion)
  or a hash of ins...
Positioning moved into Element

• Positioning methods in Element
 • absolutize, relativize
 • getOffsetParent
 • cumulativ...
Viewport inspection

• document.viewport
 • getDimensions, getWidth, getHeight
• Also remember Element.viewportOffset
• If...
JSON support, basic math methods

• JSON support
 • Object.toJSON
 • toJSON for Date, Array, Number, Hash, String
 • Strin...
Safer Hash and improved serialization

• New Hash
 • Essentially we wanted you to be able to store anything
  • Functions/...
More versatile grep

• Extended Enumerable#grep semantics
 • Used to toString() items and apply a regex on these
 • Now us...
Improved Template

• Allows deep access to interpolated object using []
 and . operators
 var speaker = {
    name: 'Chris...
Improved Template

• Only for properties.
 • If you need method calls, equip your topmost object with a
   toTemplateRepla...
And so much more…

• String#interpolate: one-shot templating
 '#{name} is #{age} years old'.interpolate(speaker)


• Objec...
And so much more…

• Array#intersect
 [1, 2, 3, 4, 5, 6].intersect([3, 5, 7]) // => [3, 5]


• Element.identify
 • Ensure ...
The future of Prototype
Some serious flux recently…

• 2008 has been an odd year for us
• GitHub + LightHouse + dayjob overloads = ?!?
• 1.6.0.2 w...
Prototype 1.6.0.4

• Significant bugfix / perffix release
• Backward-compatible, obviously
• General directions
 • Massive...
Prototype 1.6.1

• The next 3-digit release will be awesome
• General directions*
 • Massive code restructuration and patt...
Prototype 1.6.1

• When? When, when, when, when, when?
 • Er…
 • When it’s ready?
• We’d love to ship that before 2008 is ...
Prototype 2

• “Holy XHR, they’ve changed everything!”
 • Yes, but we won’t b0rk your scripts!
• General directions:
 • Wa...
The future of script.aculo.us
Scripty2

• Currently it’s “just” effects
 • 100% new effects engine, custom events-rich
 • Debug facility lets us slow do...
Scripty2 • A few demos

• Twistory
 • http://twistori.com
• Creative Scrape
 • http://creativescrape.com
• Coming-up “Prog...
Shameless plug

• Fully up-to-date on Prototype 1.6
 and script.aculo.us 1.8
• Full API reference
• Tons of examples / use...
Fair-trade plug

• Andrew Dupont’s recent book
• An ideal complement to mine
• Tackles the APIs in a different,
 very goal...
Audience Response

Questions, guys?




                   ?
On to some tech demos and
lunch! Enjoy, everyone.
Upcoming SlideShare
Loading in...5
×

What's up with Prototype and script.aculo.us?

2,799

Published on

This session of The Ajax Experience 2008 takes a look at the latest features in both Prototype and script.aculo.us, including custom events and how to leverage them, method wrapping for AOP-style programming, sprockets, the refactorings and improvements on Ajax, scheduling and the DOM, the new effects engine, and more.

We wrap up with an overview of the community landscape for these libraries, looking at major helpful resources, prominent peripheral frameworks, and seeing what the future looks like for both Prototype and script.aculo.us.

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

  • Be the first to like this

No Downloads
Views
Total Views
2,799
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
41
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

What's up with Prototype and script.aculo.us?

  1. 1. What’s up with Prototype and script.aculo.us? (Shiny things in Spinoffsland) Christophe Porteneuve CTO, Ciblo.net + Prototype Core member
  2. 2. Did you guys catch our Prototype Developer Day? • That was on Monday morning • Bringing the community together • Discussing contributions (to code, to docs) • Several Prototype Core members • Large Q&A session • Awesome stuff!
  3. 3. What we’re going to see • Prototype 1.6 → 1.6.0.3 • Custom events • Class system • Other various improvements • Where Prototype’s headed • Prototype 1.6.1 then 2.0 • Sprockets, PDoc • Where script.aculo.us is headed (Scripty2)
  4. 4. Prototype 1.6
  5. 5. Prototype 1.6 • “Hey, that was almost a year ago!” • Yeah, but never discussed at TAE yet (plus, 1.6.0.3 now…) • And a lot of good stuff in there! • Custom events and dom:loaded • New class system, with inheritance • New Function-related stuff • Ajax.Response • Countless other improvements and fixes
  6. 6. Custom events: overview • Events our own JS code triggers • Attached to DOM nodes • Bubble like regular DOM events • Publish/subscribe model: fire/observe • Major benefits • Encapsulation (internal behaviors are not exposed) • Loose coupling (anyone can trigger/observe any event) • Ability to bubble favors event delegation
  7. 7. Custom events: naming and availability • How do we tell a custom event from a native one? • The custom event’s name must have 1+ colon • e.g. dom:loaded, content:updated, effect:finished • You don’t need to “register” the event • You just observe / fire it. • Custom events available on… • Any DOM node • The document object
  8. 8. Custom events: “creating” them • Just observe one somewhere in your code initComputation: function() { var target = this.element.down('.computed'), that = this; function recompute() { target.update(that.getComputedValue()); } document.observe('data:changed', recompute); }
  9. 9. Custom events: triggering them • Simply call fire on the relevant DOM element new Field.Observer('edtReqTaxRate', 0.5, function(field, value) { field.fire('data:changed'); });
  10. 10. Custom events: the memo property initComputation: function() { var target = this.element.down('.computed'), that = this; function recompute(e) { target.update(e && e.memo ? e.memo : that.options.value); } recompute(); document.observe('data:changed', recompute); } new Field.Observer('edtReqTaxRate', 0.5, function(field, value) { field.fire('data:changed', value); });
  11. 11. Custom events: already much in style • Especially by UI-oriented third-party libraries • Lets them create a full communication scheme between their widgets with no coupling whatsoever • Prototype UI • http://prototype-ui.com • LivePipe UI (f.k.a. Control.Suite) • http://livepipe.net/
  12. 12. dom:loaded • Our first “standard” custom event • Triggers right after DOM load • So just forget Event.observe(window, 'load', initPage); • And use document.observe('dom:loaded', initPage);
  13. 13. A note about stopObserving • You can make partial calls now • Omit the handler myEditor.stopObserving('change'); • All handlers for this event on this element • Omit the event too myEditor.stopObserving(); • All handlers on all events on this element • Easier cleanup
  14. 14. More Event goodness • Guaranteed even methods and properties • relatedTarget, pageX, pageY • stopPropagation(), preventDefault(), stopped • Click detection • isLeftClick(), isMiddleClick(), isRightClick() • Pointer position • pointer(), pointerX(), pointerY()
  15. 15. A note on event binding • Pre-1.6, handlers were “unbound” by default • Unless you had bound them explicitly, they’d end up using the window scope • Starting with 1.6, handlers are bound to the subject of your observe call by default • If you bound them explicitly, as always, that prior binding will be retained.
  16. 16. New class system • The idea: ease up traditional OOP constructs and behaviors • Inheritance • Mix-ins • Method overriding with access to inherited version • Backward-compatible API
  17. 17. Ye Olde Class var MyClass = Class.create({ initialize: function(…) { • Key issues: // “Constructor” code here • initialize required, }, even if empty publicMethod1: function(…) { }, • Can’t give a parent class … }); • Can’t override methods easily
  18. 18. The new class syntax var MyClass = Class.create([parentClass, ][mixIns…, ]{ [initialize: function(…) { … },] publicMethod1: …, … }) • We can provide a single parent class • We then handle the prototype chaining for it • We can provide 1+ “mixins” (modules) • Bunches of methods that get blended in the prototype. • initialize is optional (an empty one will fill in)
  19. 19. Inheritance becomes a breeze var XMLParser = Class.create({ initialize: function(source) { … }, … }); var XHTMLParser = Class.create(XMLParser, { … }); var AtomParser = Class.create(XMLParser, { … });
  20. 20. Free stuff you get • Every instance has a constructor • Every class has a superclass and subclasses XMLParser.superclass // => null XHTMLParser.superclass // => XMLParser AtomParser.superclass // => XMLParser XMLParser.subclasses // => [XHTMLParser, AtomParser] var parser = new XHTMLParser(someXHTMLSource); parser.constructor // => XHTMLParser parser.constructor.superclass // => XMLParser
  21. 21. Mixing in modules • A module is just a bag of properties/methods • You can mix as many of those as you want at class creation time. var FeedAnalyzer = { // methods… }; … var AtomParser = Class.create(XMLParser, FeedAnalyzer, MarkupFixer, StandardNamespaceHandler, { … });
  22. 22. Class methods • These are just methods on the Class object itself, so we can resort to good ol’ Object.extend. var MyGenericClassMethods = { // methods… }; … Object.extend(AtomParser, MyGenericClassMethods); Object.extend(AtomParser, { adHocMethod1: …, adHocMethod2: …, … });
  23. 23. Adding methods post-declaration • Every class has a addMethods method that mixes anything module-like in. • It’s actually used on your modules (and custom methods) at creation time. var UberCoolMethodsIGotJustNow = { leverageMicroFormats: …, turnIntoiPhoneUIs: …, turnIntoUniversalWidgets: … }; AtomParser.addMethods(UberCoolMethodsIGotJustNow);
  24. 24. Accessing overridden methods • Insert a $super first argument. That’s it. var XMLParser = Class.create({ initialize: function(source) { … }, … }); var AtomParser = Class.create({ initialize: function($super, source, options) { $super(source); // Handle options }, … });
  25. 25. Function-fu • Prototype 1.6 introduced a lot of new methods on function so you can reduce custom anonymous wrappers and go wild (but reasonable) with AOP • curry, rescuer of useless binds • delay and defer, because patience is a virtue • wrap, because AOP / Decorator can rock • argumentNames (aka Hackish The First)
  26. 26. Spicying up your code with curry • You know how you always use bind(null,…) just because you need partial application? $('preview').observe('mousewheel:up', shiftZoom.bind(null, 125)); $('preview').observe('mousewheel:down', shiftZoom.bind(null, 80)); • Don’t do it. • That’s what curry is for: $('preview').observe('mousewheel:up', shiftZoom.curry(125)); $('preview').observe('mousewheel:down', shiftZoom.curry(80));
  27. 27. curry vs. bind • You should use bind when… • You actually need to bind (set the semantics of this) • It doesn’t matter whether you want to pre-fill arguments! • You should use curry when… • You need to pre-fill arguments • And you don’t care about the binding, or more specifically don’t want to change it.
  28. 28. Deferring execution: delay and defer • Schedule execution of a snippet of JS for later • Either a specific time later • Or ASAP—typically right after the DOM got a moment to breathe in your recent updates • function.delay(seconds) • defer is the “ASAP” case, and is just… • delay.curry(0.1) :-) • Essentially works because of single-threadedness
  29. 29. Classical defer use-case • You just added to the DOM • You need to manipulate the added fragment now • Attach event listener, manipulate its styling, whatever • Most of the time you’ll need to let the browser “catch its breath” • So your DOM addition is actually processed and available through the scripting interfaces.
  30. 30. Classical defer use-case function addAndBindForm(formMarkup) { $('formsContainer').insert(formMarkup); $('formsContainer').down('form:last-of-type'). observe('submit', genericFormValidate); } Ouch! Likely won’t return your form! function addAndBindForm(formMarkup) { $('formsContainer').insert(formMarkup); (function() { $('formsContainer').down('form:last-of-type'). observe('submit', genericFormValidate); }).defer();
  31. 31. Going AOP / Decorator with wrap • Replacing a method with an augmented version of it, which means you get a reference to the former version. if (Prototype.Browser.IE) { // Strip handlers on newly-removed elements to prevent memory leaks Element.Methods.update = Element.Methods.update.wrap( function(proceed, element, contents) { Element.select(element, '*').each(Event.stopObserving); return proceed(element, contents); } ); }
  32. 32. argumentNames • Array of argument names for a given function • Hackish: relies on functions’ toString() capability • Won’t work once packed in a name-changing way (e.g. ShrinkSafe) • Won’t work on lightened-up JS runtimes (e.g. versions of Opera Mobile) • We’re using it for our $super trick • But we should stop, and will find another way
  33. 33. Ajax.Response • Encapsulates the whole response you get • Headers + body • Extracts relevant-type contents • responseText, responseXML, responseJSON • “Shields” header retrieval • Exceptions on native fetching turn into nulls • You get that in callbacks instead of your requester • API-compatible, but adds stuff
  34. 34. Before/after 1.6 for response analysis Before 1.6 Since 1.6 callback(requester, headerJSON) callback(response, headerJSON) Watch when you’re grabbing Properties defined only once they properties make sense headerJSON, responseJSON, No JSON support sanitizeJSON/evalJSON options Automatic JS evaluation evalJS = false|true|force Property fetching can raise Fetch wrappers return '' or null exceptions when necessary.
  35. 35. Content insertion • Element.insert/wrap • insert now takes either a single element (bottom insertion) or a hash of insertions (positional keys) • wrap puts your element within another one (bottom insertion) and returns, exceptionally, the wrapper (not the element you called wrap on).
  36. 36. Positioning moved into Element • Positioning methods in Element • absolutize, relativize • getOffsetParent • cumulativeScrollOffset, cumulativeOffset, positionedOffset, viewportOffset • clonePosition • This will likely all move, with dimensioning methods, into a separate object in 1.6.1.
  37. 37. Viewport inspection • document.viewport • getDimensions, getWidth, getHeight • Also remember Element.viewportOffset • If you cache it, you should probably listen for window resize events and update your cache accordingly.
  38. 38. JSON support, basic math methods • JSON support • Object.toJSON • toJSON for Date, Array, Number, Hash, String • String has evalJSON, isJSON and unfilterJSON • As we saw, Ajax.Response had dedicated stuff • Methodized usual math on Number • abs, round, ceil, floor • e.g. myNumber.abs(), (5.42).floor()
  39. 39. Safer Hash and improved serialization • New Hash • Essentially we wanted you to be able to store anything • Functions/methods, stuff whose names clash against builtins… • So we stopped storing on the Hash itself and use internal storage • get/set/unset/index • Improved form serialization • W3C specs by the book (buttons, null/disabled/readonly…)
  40. 40. More versatile grep • Extended Enumerable#grep semantics • Used to toString() items and apply a regex on these • Now uses its argument’s match method on items • Backwards-compatible (RegExp.match is RegExp.test) • Much more versatile. Consider Selector#match…
  41. 41. Improved Template • Allows deep access to interpolated object using [] and . operators var speaker = { name: 'Christophe', age: 30, sessions: [ { title: 'PDD', time: 'Monday at 8:00am' }, { title: 'Shiny…', time: 'Wednesday at 11:05am' } ] }; var tpl = new Template('#{name}, #{age}, will speak #{sessions.length} time(s), starting on #{sessions[0].time} about #{sessions[0].title}.'); tpl.evaluate(speaker) // => quot;Christophe, 30, will speak 2 time(s), starting on Monday at 8:00am about PDDquot;
  42. 42. Improved Template • Only for properties. • If you need method calls, equip your topmost object with a toTemplateReplacements() method. var speaker = { … toTemplateReplacements: function() { var scount = this.sessions.length; return Object.extend({ sessionCount: scount + ' time' + (scount > 1 ? 's' : '') }, this); } }; var tpl = new Template('#{name}, #{age}, will speak #{sessionCount}, starting on #{sessions[0].time} about #{sessions[0].title}.');
  43. 43. And so much more… • String#interpolate: one-shot templating '#{name} is #{age} years old'.interpolate(speaker) • Object.isXxx • isElement, isArray, isHash, isFunction, isString, isNumber, isUndefined • Node constants • Guaranteed Node namespace and node type constants, from ELEMENT_NODE to NOTATION_NODE
  44. 44. And so much more… • Array#intersect [1, 2, 3, 4, 5, 6].intersect([3, 5, 7]) // => [3, 5] • Element.identify • Ensure you’ve got an ID in the end • Element.setStyle(cssString) • If you’re hardcoding it, can be nicer than a hash • Is even usually faster!
  45. 45. The future of Prototype
  46. 46. Some serious flux recently… • 2008 has been an odd year for us • GitHub + LightHouse + dayjob overloads = ?!? • 1.6.0.2 was released on January 25 • 1.6.0.3 was released on… September 29! • We’re resuming active work now… • On a more solid ground (back to our strong policies) • With more community involvement (docs/tests/code/etc.)
  47. 47. Prototype 1.6.0.4 • Significant bugfix / perffix release • Backward-compatible, obviously • General directions • Massive code restructuration and pattern-based cleanup • Most notably rewrite of DOM and Event modules • Dozens of pending patches scheduled for upgraded commit • Ideally, should release before mid-November 2008
  48. 48. Prototype 1.6.1 • The next 3-digit release will be awesome • General directions* • Massive code restructuration and pattern-based cleanup • Stronger, better-quality versions of 80+ pending patches • More builtin custom events (e.g. content changes) • Ajax timeouts • Full-spectrum positioning/dimensioning (aka “layout”) lookup and modification * As always, subject to change…
  49. 49. Prototype 1.6.1 • When? When, when, when, when, when? • Er… • When it’s ready? • We’d love to ship that before 2008 is over • But as always, we’ll ship when it’s done • Still, we’re going to work our asses off. Honest. * As always, subject to change…
  50. 50. Prototype 2 • “Holy XHR, they’ve changed everything!” • Yes, but we won’t b0rk your scripts! • General directions: • Way more modular • As everyone won’t have to grab full payload, hitherto discarded feature ideas could become “official modules.” • Better class system (no “$super”, truer encapsulation, etc.) • Perhaps stop extending DOM prototypes and find an API- compatible way to get the same code feel
  51. 51. The future of script.aculo.us
  52. 52. Scripty2 • Currently it’s “just” effects • 100% new effects engine, custom events-rich • Debug facility lets us slow down, step through, etc. • Jaw-droppin’ awesome, but not quite finalized yet • Current state on GitHub • Coming soon: • 100% new drag-and-drop module • Behaviors module (might end up shared with Prototype 2)
  53. 53. Scripty2 • A few demos • Twistory • http://twistori.com • Creative Scrape • http://creativescrape.com • Coming-up “Progress” for the Sunlight Foundation • Local demo
  54. 54. Shameless plug • Fully up-to-date on Prototype 1.6 and script.aculo.us 1.8 • Full API reference • Tons of examples / use cases • More content and “Neuron Workout” solutions at http://thebungeebook.net/ http://books.pragprog.com/titles/cppsu
  55. 55. Fair-trade plug • Andrew Dupont’s recent book • An ideal complement to mine • Tackles the APIs in a different, very goal-oriented way • Just like TBB, available as PDF and in print http://apress.com/book/view/1590599195
  56. 56. Audience Response Questions, guys? ?
  57. 57. On to some tech demos and lunch! Enjoy, everyone.
  1. A particular slide catching your eye?

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

×