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

Transcript
Page 1: What's up with Prototype and script.aculo.us?

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

Christophe PorteneuveCTO, Ciblo.net + Prototype Core member

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

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!

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

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)

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

Prototype 1.6

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

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

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

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

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

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

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

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

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

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

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

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

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

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/

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

dom:loaded

• Our first “standard” custom event

• Triggers right after DOM load

• So just forget

• And use

Event.observe(window, 'load', initPage);

document.observe('dom:loaded', initPage);

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

A note about stopObserving

• You can make partial calls now

• Omit the handler

• All handlers for this event on this element

• Omit the event too

• All handlers on all events on this element

• Easier cleanup

myEditor.stopObserving('change');

myEditor.stopObserving();

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

More Event goodness

• Guaranteed even methods and properties

• relatedTarget, pageX, pageY

• stopPropagation(), preventDefault(), stopped

• Click detection

• isLeftClick(), isMiddleClick(), isRightClick()

• Pointer position

• pointer(), pointerX(), pointerY()

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

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.

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

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

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

Ye Olde Class

• Key issues:

• initialize required,

even if empty

• Can’t give a parent

class

• Can’t override

methods easily

var MyClass = Class.create({ initialize: function(…) { // “Constructor” code here },

publicMethod1: function(…) { },

…});

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

The new class syntax

• 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)

var MyClass = Class.create([parentClass, ][mixIns…, ]{ [initialize: function(…) { … },] publicMethod1: …, …})

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

Inheritance becomes a breeze

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

var XHTMLParser = Class.create(XMLParser, { …});

var AtomParser = Class.create(XMLParser, { …});

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

Free stuff you get

• Every instance has a constructor• Every class has a superclass and subclassesXMLParser.superclass // => nullXHTMLParser.superclass // => XMLParserAtomParser.superclass // => XMLParserXMLParser.subclasses // => [XHTMLParser, AtomParser]

var parser = new XHTMLParser(someXHTMLSource);

parser.constructor // => XHTMLParserparser.constructor.superclass // => XMLParser

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

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, { …});

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

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: …, …});

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

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

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

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 }, …});

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

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)

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

Spicying up your code with curry

• You know how you always use bind(null,…) just

because you need partial application?

• Don’t do it.

• That’s what curry is for:

$('preview').observe('mousewheel:up', shiftZoom.bind(null, 125));$('preview').observe('mousewheel:down', shiftZoom.bind(null, 80));

$('preview').observe('mousewheel:up', shiftZoom.curry(125));$('preview').observe('mousewheel:down', shiftZoom.curry(80));

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

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.

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

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

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

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.

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

Classical defer use-case

function addAndBindForm(formMarkup) { $('formsContainer').insert(formMarkup); $('formsContainer').down('form:last-of-type'). observe('submit', genericFormValidate);}

function addAndBindForm(formMarkup) { $('formsContainer').insert(formMarkup); (function() { $('formsContainer').down('form:last-of-type'). observe('submit', genericFormValidate); }).defer();

Ouch! Likely won’t return your form!

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

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

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

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

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

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

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

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

Properties defined only once they make sense

No JSON supportheaderJSON, responseJSON,

sanitizeJSON/evalJSON options

Automatic JS evaluation evalJS = false|true|force

Property fetching can raise exceptions

Fetch wrappers return '' or null when necessary.

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

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

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

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.

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

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.

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

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()

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

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…)

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

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…

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

Improved Template

• Allows deep access to interpolated object using []

and . operatorsvar 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)// => "Christophe, 30, will speak 2 time(s), starting on Monday at 8:00am about PDD"

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

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

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

And so much more…

• String#interpolate: one-shot templating

• Object.isXxx

• isElement, isArray, isHash, isFunction, isString,

isNumber, isUndefined

• Node constants

• Guaranteed Node namespace and node type constants, from

ELEMENT_NODE to NOTATION_NODE

'#{name} is #{age} years old'.interpolate(speaker)

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

And so much more…

• Array#intersect

• 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!

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

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

The future of Prototype

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

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

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

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

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

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…

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

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…

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

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

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

The future of script.aculo.us

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

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)

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

Scripty2 • A few demos

• Twistory

• http://twistori.com

• Creative Scrape

• http://creativescrape.com

• Coming-up “Progress” for the Sunlight Foundation

• Local demo

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

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

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

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

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

Audience Response

Questions, guys?

?

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

On to some tech demos and lunch! Enjoy, everyone.