NinjaScript is a javascript framework for enriching web applications with unobtrusive, persistent JavaScript behavior.
Mizugumo is a ruby gem to making completely gracefully-degrading Rails applications. It uses the NinjaScript framework for rich behavior and integrates it tightly with Rails.
This presentation was given to LA RubyConf on February 5, 2011.
18. DOM Reconstruction and
Event Bindings
• Bind a tooltip behavior div#content
to $(‘.has_tooltip’)
a.has_tooltip a.has_tooltip
19. DOM Reconstruction and
Event Bindings
• Bind a tooltip behavior div#content
to $(‘.has_tooltip’)
• Dynamically add a
new .tooltip element a.has_tooltip a.has_tooltip
a.has_tooltip
20. DOM Reconstruction and
Event Bindings
• Bind a tooltip behavior div#content
to $(‘.has_tooltip’)
• Dynamically add a
new .tooltip element a.has_tooltip a.has_tooltip
• New element has no
bound event handler! a.has_tooltip
21. DOM Reconstruction and
Event Bindings
• Bind a tooltip behavior div#content
to $(‘.has_tooltip’)
• Dynamically add a
new .tooltip element a.has_tooltip a.has_tooltip
• New element has no
bound event handler! a.has_tooltip
• This is really lame ...
27. Solution 1:
Event Delegation
• jQuery live() and similar
28. Solution 1:
Event Delegation
• jQuery live() and similar
• Bind handlers to root element of the
DOM
29. Solution 1:
Event Delegation
• jQuery live() and similar
• Bind handlers to root element of the
DOM
• Since browsers bubble unhandled events
up the DOM, the root handles all events
30. Solution 1:
Event Delegation
• jQuery live() and similar
• Bind handlers to root element of the
DOM
• Since browsers bubble unhandled events
up the DOM, the root handles all events
This is pretty awesome.
32. The Problem with
Event Delegation
• live() can’t handle element transformations
33. The Problem with
Event Delegation
• live() can’t handle element transformations
• ... like giving <div>s rounded corners ...
34. The Problem with
Event Delegation
• live() can’t handle element transformations
• ... like giving <div>s rounded corners ...
• Because there’s no event to process when
we insert new elements into the DOM
35. The Problem with
Event Delegation
• live() can’t handle element transformations
• ... like giving <div>s rounded corners ...
• Because there’s no event to process when
we insert new elements into the DOM
• DOM Level 2-compliant browsers are suppossed
to send DOMSubtreeModified and
DOMNodeInserted
36. The Problem with
Event Delegation
• live() can’t handle element transformations
• ... like giving <div>s rounded corners ...
• Because there’s no event to process when
we insert new elements into the DOM
• DOM Level 2-compliant browsers are suppossed
to send DOMSubtreeModified and
DOMNodeInserted
... bad IE. No Biscuit!
38. Solution 1I:
Automatic Rebinding
• Bind to and/or transform the element,
not the root.
39. Solution 1I:
Automatic Rebinding
• Bind to and/or transform the element,
not the root.
• NinjaScript examines new DOM
elements to see if any known behaviors
match.
40. Solution 1I:
Automatic Rebinding
• Bind to and/or transform the element,
not the root.
• NinjaScript examines new DOM
elements to see if any known behaviors
match.
• NinjaScript fires its own event when the
DOM is reconstructed so it works in IE.
44. Defining a Behavior
Ninja.behavior({
'.awesome': {
transform: function(elem){... add to the DOM ...},
events: {
click: function(event){... handle click ...},
mouseover: function(event){... pop tooltip ...}
}
}
})
All awesome elements will get the transform
applied, no matter when they’re added.
45. Defining a Behavior
Shortcut: skip the ‘events:’ mapping if you’re
just handling an event.
Ninja.behavior({
'.awesome': {
click: function(event){ ... handle click ...},
}
})
47. Reusable Behaviors
You can easily define and name behaviors for
reuse. singsAndDances(){
function
return new ninja.does({
transform: function(elem) { elem.addATutu() },
click: function(event)
{ this.element.pirouette() },
mouseover: function(event)
{ this.element.singAnAria()}
})
}
48. Reusable Behaviors
You can easily define and name behaviors for
reuse. singsAndDances(){
function
return new ninja.does({
transform: function(elem) { elem.addATutu() },
click: function(event)
{ this.element.pirouette() },
mouseover: function(event)
{ this.element.singAnAria()}
})
}
Ninja.behavior({
‘#dhh’: Ninja.singsAndDances(),
‘#katz’: Ninja.singsAndDances(),
‘.code_monkey’: Ninja.singsAndDances()
})
49. Pre-Defined Behaviors
These work today - built into NinjaScript
• submitsAsAjax (for forms or links)
• becomesLink (for forms)
• decays (fades away after 10
sec)
• isWatermarked (for form inputs)
56. Future Plans for
NinjaScript
• Lots more prepackaged behaviors
• Decouple from jQuery - build NinjaScript
behaviors in any framework
57. Future Plans for
NinjaScript
• Lots more prepackaged behaviors
• Decouple from jQuery - build NinjaScript
behaviors in any framework
• Handle JSON returns from AJAX calls,
not just eval()
70. The Rails 3 RESTfail
• Simulate PUT and DELETE methods!
71. The Rails 3 RESTfail
• Simulate PUT and DELETE methods!
• link_to(:method => ‘delete’)
72. The Rails 3 RESTfail
• Simulate PUT and DELETE methods!
• link_to(:method => ‘delete’)
• <a href=’/product/1’ data-
method=‘delete‘>
73. The Rails 3 RESTfail
• Simulate PUT and DELETE methods!
• link_to(:method => ‘delete’)
• <a href=’/product/1’ data-
method=‘delete‘>
• Without JS, it’s a show link!
74. The Rails 3 RESTfail
• Simulate PUT and DELETE methods!
• link_to(:method => ‘delete’)
• <a href=’/product/1’ data-
method=‘delete‘>
• Without JS, it’s a show link!
• ... oops!
76. The Mizugumo Way
link_to with :method => ‘delete’
<%= link_to ‘click me’, ‘/foo’, :method => :delete %>
77. The Mizugumo Way
link_to with :method => ‘delete’
<%= link_to ‘click me’, ‘/foo’, :method => :delete %>
Generates a <form>!
<form action=’/foo’ method=‘post’
class=‘mizugumo_graceful_form’>
<input type=‘hidden’ name=‘_method’ value=‘delete’>
<input type=‘submit’ value=’click me’>
</a>
78.
79. The Mizugumo Way
But a default NinjaScript behavior:
Ninja.behavior({
‘.mizugumo_graceful_form’: becomesLink
})
80. The Mizugumo Way
But a default NinjaScript behavior:
Ninja.behavior({
‘.mizugumo_graceful_form’: becomesLink
})
Converts it back!
<a href=’/foo’>click me</a>