mizugumo 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +12 -1
- data/README.rdoc +67 -2
- data/doc/NAME.haml +14 -0
- data/doc/PURPOSE.haml +71 -0
- data/doc/making_generators.txt +45 -0
- data/lib/generators/mizugumo/install/install_generator.rb +5 -3
- data/lib/generators/mizugumo/install/templates/javascripts/jquery.ninja_script.js +197 -160
- data/lib/generators/mizugumo/install/templates/javascripts/rails.js +132 -0
- data/lib/mizugumo_link_helper.rb +3 -0
- metadata +10 -6
data/LICENSE.txt
CHANGED
@@ -1,4 +1,15 @@
|
|
1
|
-
Copyright (c) 2011 Evan Dorn
|
1
|
+
Copyright (c) 2011 Evan Dorn and Logical Reality Design
|
2
|
+
|
3
|
+
Includes a copy of NinjaScript, itself copyright (c) 2010-2011 Judson Lester and Logical Reality Design
|
4
|
+
|
5
|
+
Includes a copy of jQuery 1.4.2, Copyright 2010 John Resig
|
6
|
+
Dual licensed under the MIT or GPL Version 2 licenses.
|
7
|
+
http://jquery.org/license
|
8
|
+
|
9
|
+
Includes a copy of a jQuery-1.4.2 - compatible implementation of
|
10
|
+
Rails 3's 'rails.js', available from: https://gist.github.com/704387
|
11
|
+
|
12
|
+
--------------------------------------------------------------------
|
2
13
|
|
3
14
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
15
|
a copy of this software and associated documentation files (the
|
data/README.rdoc
CHANGED
@@ -6,11 +6,21 @@ Mizugumo is a gem designed to provide Rails with JavaScript and AJAX behavior th
|
|
6
6
|
* gracefully-degrading: defaults to fully functional and
|
7
7
|
sensible page-reload behavior when javascript is not available.
|
8
8
|
|
9
|
+
See a demo running at:
|
10
|
+
http://mizugumo-demo.lrdesign.com
|
11
|
+
Or download the code for the demo at:
|
12
|
+
https://github.com/LRDesign/mizugumo_demo
|
13
|
+
|
9
14
|
Mizugumo uses NinjaScript by Judson Lester to provide unobtrusive JS behaviors. For more info, see:
|
10
15
|
git@github.com:LRDesign/NinjaScript.git
|
11
16
|
|
12
|
-
|
13
|
-
|
17
|
+
== WARNINGS
|
18
|
+
|
19
|
+
In the current (early release) version, Mizugumo and NinjaScript have some limitations. Notably, in this version they will clobber the normal rails.js and prevent its behaviors from
|
20
|
+
working. The installer will copy a jQuery-compatible version of rails.js that you should
|
21
|
+
use instead if you depend on Rails' default (semi-obtrusive) approaches to AJAX, link_to with :confirm =>'Are you sure?' and similar things working.
|
22
|
+
|
23
|
+
In addition, NinjaScript currently requires jQuery 1.4.2. It is NOT compatible with the current version of jQuery, 1.4.4, or the development version 1.5. We are eagerly working on a fix.
|
14
24
|
|
15
25
|
== Features
|
16
26
|
|
@@ -51,6 +61,53 @@ NOTE: If you still have javascript_include_tag :defaults, you probably want to
|
|
51
61
|
Ninjascript is meant to work with jQuery, and we don't know what happens if you try to run it
|
52
62
|
side-by-side with Prototype.
|
53
63
|
|
64
|
+
== Graceful degradation of :method => 'delete' (or PUT, or POST) links
|
65
|
+
|
66
|
+
Rails' concept of REST runs headlong into the desire to make a site degrade
|
67
|
+
gracefully. Specifically, the link_to() helper, when passed a method other
|
68
|
+
than 'get', outputs a link with a data-method attribute that won't work
|
69
|
+
when JS is absent. To wit: link_to('Delete Item', @item, :method => 'delete') in rails outputs this:
|
70
|
+
|
71
|
+
<a href='/items/1' data-method='delete'>Delete Item</a>
|
72
|
+
|
73
|
+
When JS isn't available, this delete link acts as a show link. This is bad,
|
74
|
+
bad, bad. What's worse, Rails' scaffold generator makes these exact links
|
75
|
+
ubiquitous.
|
76
|
+
|
77
|
+
When Mizugumo is installed, that same helper instead outputs this:
|
78
|
+
|
79
|
+
<form action='/items/1' class="mizugumo_graceful_form">
|
80
|
+
<input type='hidden' name='_method' value='delete'>
|
81
|
+
<input type='submit' value='Delete Item'>
|
82
|
+
</form>
|
83
|
+
|
84
|
+
This gives the user a button instead of a form ... but it works without JS
|
85
|
+
running. Then, to give JS users the behavior the developer intended,
|
86
|
+
Mizugumo appends this to your application.js:
|
87
|
+
|
88
|
+
Ninja.behavior({
|
89
|
+
'.mizugumo_graceful_form': Ninja.becomesLink
|
90
|
+
})
|
91
|
+
|
92
|
+
This NinjaScript behavior converts that form back into a link. The JS user
|
93
|
+
sees no difference whatsoever, but the link at least *works* for the non-JS
|
94
|
+
user.
|
95
|
+
|
96
|
+
This behavior will work for :method => 'put' and :method => 'post' as well,
|
97
|
+
and it supports links whose content is an image as well; creating an image
|
98
|
+
submit button in the form rather than a text submit button.
|
99
|
+
|
100
|
+
WARNING: This cycle won't work if your link has complex content with html
|
101
|
+
structure; for example if you write
|
102
|
+
|
103
|
+
link_to('some <b>content</b><img src="foo">and text', @item, :method => 'delete' )
|
104
|
+
|
105
|
+
Mizugomo will not be able to preserve all that content through the degraded
|
106
|
+
form. However, we think this is a rare case. If you aren't passing :method
|
107
|
+
to your link_to, mizugumo will ignore it entirely, so you can still create
|
108
|
+
complex GET links.
|
109
|
+
|
110
|
+
|
54
111
|
== Scaffold generator
|
55
112
|
|
56
113
|
Mizugumo ships with a scaffold generator that builds out-of-the-box AJAX/UJS scaffolds that degrade gracefully in the absence of JavaScript. To use it, add this to config/application.rb:
|
@@ -72,6 +129,8 @@ For HAML views:
|
|
72
129
|
|
73
130
|
== Contributing to Mizugumo
|
74
131
|
|
132
|
+
* Install MizugumoDemo and make sure that its tests still pass with your version of Mizugumo!
|
133
|
+
|
75
134
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
76
135
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
77
136
|
* Fork the project
|
@@ -80,8 +139,14 @@ For HAML views:
|
|
80
139
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
81
140
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
82
141
|
|
142
|
+
== Reporting Bugs
|
143
|
+
|
144
|
+
Use the GitHub issue tracker.
|
145
|
+
|
83
146
|
== Copyright
|
84
147
|
|
85
148
|
Copyright (c) 2011 Evan Dorn and Logical Reality design. See LICENSE.txt for
|
86
149
|
further details.
|
87
150
|
|
151
|
+
Web Development by Logical Reality Design: http://LRDesign.com
|
152
|
+
|
data/doc/NAME.haml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
%h1 Mizugumo Ᾱ Name
|
2
|
+
|
3
|
+
%p
|
4
|
+
'mizugumo' is Japanese for 'water-spider'. Mythologically, however, it is the
|
5
|
+
name for special wooden shoes that ninja used to walk on water and thereby approach
|
6
|
+
targets via unexpected routes.
|
7
|
+
|
8
|
+
%p
|
9
|
+
As much as the Mythbusters were not impressed (real mizugumo likely did not work
|
10
|
+
for actual water-walking, and probably only worked as snowshoes to cross marshy
|
11
|
+
terrain), we thought it an appropriate name for an unobtrusive JS behavior library.
|
12
|
+
|
13
|
+
|
14
|
+
|
data/doc/PURPOSE.haml
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
%h1 Mizugumo Ᾱ Purpose
|
2
|
+
|
3
|
+
%p
|
4
|
+
Mizugumo exists to help Rails developers quickly build apps that are both AJAXy and that degrade
|
5
|
+
gracefully when JavaScript is absent. It uses NinjaScript to provide unobtrusive javascript
|
6
|
+
behaviors.
|
7
|
+
|
8
|
+
%h2 Graceful Degradation
|
9
|
+
|
10
|
+
%h3 Why we care
|
11
|
+
|
12
|
+
%p
|
13
|
+
Rails developers are notorious for making apps that do not degrade well when JS is unavailable,
|
14
|
+
especially if the app uses AJAX for some actions. It's hard to blame anyone - generally, adding
|
15
|
+
AJAX is a bit of a pain, and adding degradation requires duplicating a lot of development.
|
16
|
+
|
17
|
+
%p
|
18
|
+
Ideally, we should put the effort into graceful degradation because we can't count on JavaScript
|
19
|
+
in real-world conditions. Some situations we care about in which JavaScript might not be
|
20
|
+
available:
|
21
|
+
|
22
|
+
%ul
|
23
|
+
%li NoScript users and other security-conscious folk
|
24
|
+
%li Screen readers for vision-impaired users
|
25
|
+
%li Search engines and spiders, which should see as accurate
|
26
|
+
%li Automation tools
|
27
|
+
|
28
|
+
%h3 How to solve the problem
|
29
|
+
|
30
|
+
%p
|
31
|
+
Because the client sees the normal, JS-enabled behavior, and because we are all busy people,
|
32
|
+
Rails developers usually won't make their sites degrade gracefully until it becomes no harder
|
33
|
+
to build in graceful degradation than not to. Mizugumo aspires to this goal.
|
34
|
+
|
35
|
+
%p
|
36
|
+
Mizugumo replaces some of rails' default behavior that depend on JS with ones that work
|
37
|
+
in the absence of JS. Specifically, link_to with a :method option other than GET actually
|
38
|
+
outputs a <form>, not an <a href='foo'>. It then provides a default javascript behavior,
|
39
|
+
written in NinjaScript, to implicitly convert those forms
|
40
|
+
|
41
|
+
%p
|
42
|
+
Mizugumo also provides a scaffold tool that gives you an out-of-the box AJAX controller
|
43
|
+
in which all actions degrade perfectly in the absence of JS. From that scaffold, it becomes
|
44
|
+
much easier to build rich behaviors into your sites while maintaining JS-less functionality.
|
45
|
+
|
46
|
+
%h2 The Philosophy of Ninja-like Unobtrusiveness
|
47
|
+
|
48
|
+
%p
|
49
|
+
The goal of Mizugumo's JS engine, NinjaScript, is to make javascript super easy to use, and
|
50
|
+
reliable for the developer &%8212; no surprises.
|
51
|
+
|
52
|
+
%3 CSS is Great, JS Sucks
|
53
|
+
|
54
|
+
%p
|
55
|
+
We take for granted CSS's super-easy behavior: specify a selector and add a style. That style
|
56
|
+
will always apply to anything that matches that selector, even if the DOM is restructured. JavaScript
|
57
|
+
is not like this, however: if we use a library (say jQuery) to bind events to a selector, event
|
58
|
+
handlers will get bound to the DOM nodes that match that selector *now*, but elements that get added
|
59
|
+
later are out of luck. We can fix event handlers with event delegation methods, but that still
|
60
|
+
doesn't help us if what we want to do is transform elements. If I write a javascript block to
|
61
|
+
add rounded corners to a bunch of elements, or to add tooltip elements to a bunch of <li> nodes,
|
62
|
+
it will only make those changes to the elements that match at the time it is run.
|
63
|
+
|
64
|
+
%p
|
65
|
+
NinjaScripts aims to make JS as much like CSS as possible: specify a behavior once - including
|
66
|
+
transformations of the elements themselves - and those behaviors will always apply to all elements
|
67
|
+
even if the elements are added to the DOM later. So you can say "all divs with class .foo
|
68
|
+
get rounded corners" or "all forms matching .mizugomo_graceful_form get replaced with
|
69
|
+
links with the text matching the submit button text" and likewise not worry about when
|
70
|
+
and how said forms get added to the DOM.
|
71
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
These are notes to myself to hopefully avoid this kind of suffering again.
|
2
|
+
|
3
|
+
I ran into some troubles (a few hours worth) trying to get the generators
|
4
|
+
working.
|
5
|
+
|
6
|
+
Rails wants to load generators from specific "namespaces", but parts of those
|
7
|
+
namespaces are automatically generated. In particular, when a generator is
|
8
|
+
invoked, it will generally be looked for with both a "base" and a "context".
|
9
|
+
Rails will use *one* of these two when looking, for example, it will look for:
|
10
|
+
|
11
|
+
<base>/<your generator> and <your generator>/<context>.
|
12
|
+
|
13
|
+
These are interdependent; particularly, setting up a scaffold_controller
|
14
|
+
generator will cause part of it's namespace to be assumed when looking for
|
15
|
+
the other items, like template_engine and test_framework.
|
16
|
+
|
17
|
+
For example, setting scaffold_generator to "ninja_helper:scaffold_controller"
|
18
|
+
will cause it to assume a base of "ninja_helper" and a context of "scaffold"
|
19
|
+
when you run "rails generate scaffold", which will make it look for your view
|
20
|
+
generator in "ninja_helper:erb" and "erb:scaffold", even if you don't explicitly
|
21
|
+
set template_engine to anything.
|
22
|
+
|
23
|
+
The fix for this was to specify the hooks for template_engine etc. with an
|
24
|
+
:in => :rails parameter which causes it to look in the rails namespace
|
25
|
+
(and thus retrieve the defaults) unless configs in application.rb specifically
|
26
|
+
override those generators.
|
27
|
+
|
28
|
+
Ultimately, Rails will generate eight acceptable namespaces for the
|
29
|
+
generator based on the requested name in config in application.rb
|
30
|
+
***It must live in one of those paths on the filesystem.*** However, the
|
31
|
+
actual ruby module namespace does not need to match (seems to be irrelevant).
|
32
|
+
The Rails 'namespace' can be massaged just by setting self.namespace(blah)
|
33
|
+
in the class, for example:
|
34
|
+
|
35
|
+
self.namespace("rails:ninja_helper:erb")
|
36
|
+
|
37
|
+
This lives in generators/rails/ninja_helper/erb_generator.rb, which is
|
38
|
+
one of the acceptable namespaces/paths for a beast with this config:
|
39
|
+
|
40
|
+
config.generators do |g|
|
41
|
+
g.template_engine 'ninja_helper:erb'
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
@@ -21,8 +21,9 @@ DESC
|
|
21
21
|
file = File.join("public", "javascripts", "application.js")
|
22
22
|
append_to_file(file) do
|
23
23
|
<<ADDITIONAL_JS
|
24
|
+
|
25
|
+
// Generated by mizugumo install script
|
24
26
|
Ninja.behavior({
|
25
|
-
// Generated by mizugumo install script
|
26
27
|
// This line enables the NH behavior of graceful degradation of method links
|
27
28
|
// to forms and back again
|
28
29
|
'.mizugumo_graceful_form': Ninja.becomesLink
|
@@ -35,14 +36,15 @@ ADDITIONAL_JS
|
|
35
36
|
say (<<NOTICE
|
36
37
|
|
37
38
|
Mizugumo is installed!
|
38
|
-
Remember to remove the default JS and link to the jQuery/NinjaScript
|
39
|
-
script and CSS files by adding these to your application layout:
|
39
|
+
Remember to remove the default JS and link to the jQuery/NinjaScript script and CSS files by adding these to your application layout:
|
40
40
|
|
41
41
|
<%= stylesheet_link_tag 'mizugumo.css' %>
|
42
42
|
<%= javascript_include_tag 'jquery-1.4.2.js' %>
|
43
43
|
<%= javascript_include_tag 'jquery.ninja_script.js' %>
|
44
|
+
<%= javascript_include_tag 'rails.js' %>
|
44
45
|
<%= javascript_include_tag 'application.js' %>
|
45
46
|
|
47
|
+
The included rails.js is a jQuery-1.4.2 compatible implementation of rails.js, and should replace the default rails.js.
|
46
48
|
If you want to use the Mizugumo AJAX scaffold generators, add this to your application.rb:
|
47
49
|
|
48
50
|
config.generators do |g|
|
@@ -1,12 +1,17 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/*
|
2
|
+
* NinjaScript - 0.8.0
|
3
|
+
* written and copyright 2010-2011 Judson Lester and Logical Reality Design
|
4
|
+
* Licensed under the MIT license
|
5
|
+
*/
|
3
6
|
Ninja = (function() {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
+
function log(message) {
|
8
|
+
if(false) { //LOGGING TURNED OFF IS 100% faster!
|
9
|
+
try {
|
10
|
+
console.log(message)
|
11
|
+
}
|
12
|
+
catch(e) {} //we're in IE or FF w/o Firebug or something
|
13
|
+
}
|
7
14
|
}
|
8
|
-
catch(e) {} //we're in IE or FF w/o Firebug or something
|
9
|
-
}
|
10
15
|
|
11
16
|
function isArray(candidate) {
|
12
17
|
return (candidate.constructor == Array)
|
@@ -69,7 +74,7 @@ Ninja = (function() {
|
|
69
74
|
collection.addBehavior(selector, dispatching[selector])
|
70
75
|
}
|
71
76
|
}
|
72
|
-
|
77
|
+
jQuery(window).load( function(){ Ninja.go() } )
|
73
78
|
},
|
74
79
|
|
75
80
|
badBehavior: function(nonsense) {
|
@@ -83,8 +88,7 @@ Ninja = (function() {
|
|
83
88
|
//If we ever receive either of the W3C DOMMutation events, we don't need our IE based
|
84
89
|
//hack, so nerf it
|
85
90
|
rootOfDocument.one("DOMSubtreeModified DOMNodeInserted", function(){
|
86
|
-
|
87
|
-
this.addMutationTargets = function(t){}
|
91
|
+
Ninja.tools.detachSyntheticMutationEvents()
|
88
92
|
})
|
89
93
|
this.behavior = this.badBehavior
|
90
94
|
this.tools.fireMutationEvent()
|
@@ -95,47 +99,20 @@ Ninja = (function() {
|
|
95
99
|
|
96
100
|
function Tools(ninja) {
|
97
101
|
this.ninja = ninja
|
98
|
-
this.mutationTargets = []
|
99
102
|
}
|
100
103
|
|
101
104
|
Tools.prototype = {
|
105
|
+
//Handy JS things
|
102
106
|
forEach: forEach,
|
103
107
|
enrich: function(left, right) {
|
104
|
-
return
|
108
|
+
return jQuery.extend(left, right)
|
105
109
|
},
|
106
110
|
ensureDefaults: function(config, defaults) {
|
107
111
|
return this.enrich(defaults, config)
|
108
112
|
},
|
109
|
-
|
110
|
-
var attributeList = []
|
111
|
-
var attrs = []
|
112
|
-
var match = new RegExp("^" + which.join("$|^") + "$")
|
113
|
-
to = $(to)
|
114
|
-
this.forEach(from.attributes, function(att) {
|
115
|
-
if(match.test(att.nodeName)) {
|
116
|
-
to.attr(att.nodeName, att.nodeValue)
|
117
|
-
}
|
118
|
-
})
|
119
|
-
},
|
120
|
-
addMutationTargets: function(targets) {
|
121
|
-
this.mutationTargets = this.mutationTargets.concat(target)
|
122
|
-
},
|
113
|
+
//DOM and Events
|
123
114
|
getRootOfDocument: function() {
|
124
|
-
return
|
125
|
-
},
|
126
|
-
fireMutationEvent: function() {
|
127
|
-
var targets = this.mutationTargets
|
128
|
-
if (targets.length > 0 ) {
|
129
|
-
for(var target = targets.shift();
|
130
|
-
targets.length > 0;
|
131
|
-
target = targets.shift()) {
|
132
|
-
$(target).trigger("thisChangedDOM")
|
133
|
-
}
|
134
|
-
}
|
135
|
-
else {
|
136
|
-
this.getRootOfDocument().trigger("thisChangedDOM")
|
137
|
-
//$("html").trigger("thisChangedDOM")
|
138
|
-
}
|
115
|
+
return jQuery("html") //document.firstChild)
|
139
116
|
},
|
140
117
|
clearRootCollection: function() {
|
141
118
|
Ninja.behavior = Ninja.goodBehavior
|
@@ -151,13 +128,6 @@ Ninja = (function() {
|
|
151
128
|
rootOfDocument.data("ninja-behavior", collection);
|
152
129
|
return collection
|
153
130
|
},
|
154
|
-
deriveElementsFrom: function(element, means){
|
155
|
-
switch(typeof means){
|
156
|
-
case 'undefined': return element
|
157
|
-
case 'string': return $(means)
|
158
|
-
case 'function': return means(element)
|
159
|
-
}
|
160
|
-
},
|
161
131
|
suppressChangeEvents: function() {
|
162
132
|
return new Behavior({
|
163
133
|
events: {
|
@@ -166,32 +136,34 @@ Ninja = (function() {
|
|
166
136
|
}
|
167
137
|
})
|
168
138
|
},
|
169
|
-
|
170
|
-
|
171
|
-
if(existing.length > 0) {
|
172
|
-
return existing[0]
|
173
|
-
}
|
174
|
-
|
175
|
-
var hide = $("<div id='ninja-hide'></div>").css("display", "none")
|
176
|
-
$("body").append(hide)
|
177
|
-
Ninja.tools.getRootCollection().applyBehaviorsTo(hide, [Ninja.tools.suppressChangeEvents()])
|
178
|
-
return hide
|
139
|
+
addMutationTargets: function(targets) {
|
140
|
+
this.getRootCollection().addMutationTargets(targets)
|
179
141
|
},
|
180
|
-
|
181
|
-
|
142
|
+
fireMutationEvent: function() {
|
143
|
+
this.getRootCollection().fireMutationEvent()
|
182
144
|
},
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
//but IE8 doesn't implement ECMA 2.6.2 5th ed.
|
187
|
-
|
188
|
-
return new Overlay(jQuery.makeArray(arguments))
|
145
|
+
detachSyntheticMutationEvents: function() {
|
146
|
+
this.getRootCollection().fireMutationEvent = function(){}
|
147
|
+
this.getRootCollection().addMutationTargets = function(t){}
|
189
148
|
},
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
149
|
+
//HTML Utils
|
150
|
+
copyAttributes: function(from, to, which) {
|
151
|
+
var attributeList = []
|
152
|
+
var attrs = []
|
153
|
+
var match = new RegExp("^" + which.join("$|^") + "$")
|
154
|
+
to = jQuery(to)
|
155
|
+
this.forEach(from.attributes, function(att) {
|
156
|
+
if(match.test(att.nodeName)) {
|
157
|
+
to.attr(att.nodeName, att.nodeValue)
|
158
|
+
}
|
159
|
+
})
|
160
|
+
},
|
161
|
+
deriveElementsFrom: function(element, means){
|
162
|
+
switch(typeof means){
|
163
|
+
case 'undefined': return element
|
164
|
+
case 'string': return jQuery(means)
|
165
|
+
case 'function': return means(element)
|
166
|
+
}
|
195
167
|
},
|
196
168
|
extractMethod: function(element, formData) {
|
197
169
|
if(element.dataset !== undefined &&
|
@@ -201,9 +173,9 @@ Ninja = (function() {
|
|
201
173
|
return element.dataset["method"]
|
202
174
|
}
|
203
175
|
if(element.dataset === undefined &&
|
204
|
-
|
205
|
-
log("Override via data-method: " +
|
206
|
-
return
|
176
|
+
jQuery(element).attr("data-method") !== undefined) {
|
177
|
+
log("Override via data-method: " + jQuery(element).attr("data-method"))
|
178
|
+
return jQuery(element).attr("data-method")
|
207
179
|
}
|
208
180
|
if(typeof formData !== "undefined") {
|
209
181
|
for(var i=0, len = formData.length; i<len; i++) {
|
@@ -218,10 +190,46 @@ Ninja = (function() {
|
|
218
190
|
}
|
219
191
|
return "GET"
|
220
192
|
},
|
193
|
+
//Ninjascript utils
|
194
|
+
applyBehaviors: function(element, behaviors) {
|
195
|
+
this.getRootCollection().apply(element, behaviors)
|
196
|
+
},
|
197
|
+
message: function(text, classes) {
|
198
|
+
var addingMessage = this.ninja.config.messageWrapping(text, classes)
|
199
|
+
jQuery(this.ninja.config.messageList).append(addingMessage)
|
200
|
+
},
|
201
|
+
hiddenDiv: function() {
|
202
|
+
var existing = jQuery("div#ninja-hide")
|
203
|
+
if(existing.length > 0) {
|
204
|
+
return existing[0]
|
205
|
+
}
|
206
|
+
|
207
|
+
var hide = jQuery("<div id='ninja-hide'></div>").css("display", "none")
|
208
|
+
jQuery("body").append(hide)
|
209
|
+
Ninja.tools.getRootCollection().applyBehaviorsTo(hide, [Ninja.tools.suppressChangeEvents()])
|
210
|
+
return hide
|
211
|
+
},
|
212
|
+
ajaxSubmitter: function(form) {
|
213
|
+
return new AjaxSubmitter(form)
|
214
|
+
},
|
215
|
+
overlay: function() {
|
216
|
+
// I really liked using
|
217
|
+
//return new Overlay([].map.apply(arguments,[function(i) {return i}]))
|
218
|
+
//but IE8 doesn't implement ECMA 2.6.2 5th ed.
|
219
|
+
|
220
|
+
return new Overlay(jQuery.makeArray(arguments))
|
221
|
+
},
|
222
|
+
busyOverlay: function(elem) {
|
223
|
+
var overlay = this.overlay(elem)
|
224
|
+
overlay.set.addClass("ninja busy")
|
225
|
+
overlay.laziness = this.ninja.config.busyLaziness
|
226
|
+
return overlay
|
227
|
+
},
|
221
228
|
//Currently, this doesn't respect changes to the original block...
|
229
|
+
//There should be an "Overlay behavior" that gets applied
|
222
230
|
buildOverlayFor: function(elem) {
|
223
|
-
var overlay =
|
224
|
-
var hideMe =
|
231
|
+
var overlay = jQuery(document.createElement("div"))
|
232
|
+
var hideMe = jQuery(elem)
|
225
233
|
var offset = hideMe.offset()
|
226
234
|
overlay.css("position", "absolute")
|
227
235
|
overlay.css("top", offset.top)
|
@@ -230,10 +238,6 @@ Ninja = (function() {
|
|
230
238
|
overlay.height(hideMe.outerHeight())
|
231
239
|
overlay.css("zIndex", "2")
|
232
240
|
return overlay
|
233
|
-
},
|
234
|
-
message: function(text, classes) {
|
235
|
-
var addingMessage = this.ninja.config.messageWrapping(text, classes)
|
236
|
-
$(this.ninja.config.messageList).append(addingMessage)
|
237
241
|
}
|
238
242
|
}
|
239
243
|
|
@@ -259,7 +263,7 @@ Ninja = (function() {
|
|
259
263
|
AjaxSubmitter.prototype = {
|
260
264
|
submit: function() {
|
261
265
|
log("Computed method: " + this.method)
|
262
|
-
|
266
|
+
jQuery.ajax(this.ajaxData())
|
263
267
|
},
|
264
268
|
|
265
269
|
ajaxData: function() {
|
@@ -302,7 +306,7 @@ Ninja = (function() {
|
|
302
306
|
var elements = this.convertToElementArray(list)
|
303
307
|
this.laziness = 0
|
304
308
|
var ov = this
|
305
|
-
this.set =
|
309
|
+
this.set = jQuery(jQuery.map(elements, function(element, idx) {
|
306
310
|
return ov.buildOverlayFor(element)
|
307
311
|
}))
|
308
312
|
}
|
@@ -313,7 +317,7 @@ Ninja = (function() {
|
|
313
317
|
switch(typeof list) {
|
314
318
|
case 'undefined': return []
|
315
319
|
case 'boolean': return []
|
316
|
-
case 'string': return h.convertToElementArray(
|
320
|
+
case 'string': return h.convertToElementArray(jQuery(list))
|
317
321
|
case 'function': return h.convertToElementArray(list())
|
318
322
|
case 'object': {
|
319
323
|
//IE8 barfs on 'list instanceof Element'
|
@@ -335,8 +339,8 @@ Ninja = (function() {
|
|
335
339
|
},
|
336
340
|
|
337
341
|
buildOverlayFor: function(elem) {
|
338
|
-
var overlay =
|
339
|
-
var hideMe =
|
342
|
+
var overlay = jQuery(document.createElement("div"))
|
343
|
+
var hideMe = jQuery(elem)
|
340
344
|
var offset = hideMe.offset()
|
341
345
|
overlay.css("position", "absolute")
|
342
346
|
overlay.css("top", offset.top)
|
@@ -348,7 +352,7 @@ Ninja = (function() {
|
|
348
352
|
return overlay[0]
|
349
353
|
},
|
350
354
|
affix: function() {
|
351
|
-
this.set.appendTo(
|
355
|
+
this.set.appendTo(jQuery("body"))
|
352
356
|
overlaySet = this.set
|
353
357
|
window.setTimeout(function() {
|
354
358
|
overlaySet.css("display", "block")
|
@@ -359,14 +363,6 @@ Ninja = (function() {
|
|
359
363
|
}
|
360
364
|
}
|
361
365
|
|
362
|
-
function BehaviorCollection() {
|
363
|
-
this.lexicalCount = 0
|
364
|
-
this.eventQueue = []
|
365
|
-
this.behaviors = {}
|
366
|
-
this.selectors = []
|
367
|
-
return this
|
368
|
-
}
|
369
|
-
|
370
366
|
function EventScribe() {
|
371
367
|
this.handlers = {}
|
372
368
|
this.currentElement = null
|
@@ -377,8 +373,8 @@ Ninja = (function() {
|
|
377
373
|
for(var eventName in this.handlers) {
|
378
374
|
var handler = this.handlers[eventName]
|
379
375
|
this.handlers[eventName] = function(eventRecord) {
|
380
|
-
handler(eventRecord)
|
381
|
-
|
376
|
+
handler.call(this, eventRecord)
|
377
|
+
jQuery(element).remove()
|
382
378
|
}
|
383
379
|
}
|
384
380
|
},
|
@@ -401,7 +397,7 @@ Ninja = (function() {
|
|
401
397
|
},
|
402
398
|
applyEventHandlers: function(element) {
|
403
399
|
for(var eventName in this.handlers) {
|
404
|
-
|
400
|
+
jQuery(element).bind(eventName, this.handlers[eventName])
|
405
401
|
}
|
406
402
|
}
|
407
403
|
}
|
@@ -413,24 +409,35 @@ Ninja = (function() {
|
|
413
409
|
this.stashedElements = []
|
414
410
|
}
|
415
411
|
|
416
|
-
RootContext.prototype =
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
412
|
+
RootContext.prototype = Ninja.tools.enrich(
|
413
|
+
new Tools(Ninja),
|
414
|
+
{
|
415
|
+
stash: function(element) {
|
416
|
+
this.stashedElements.unshift(element)
|
417
|
+
},
|
418
|
+
clearStash: function() {
|
419
|
+
this.stashedElements = []
|
420
|
+
},
|
421
|
+
//XXX Of concern: how do cascading events work out?
|
422
|
+
//Should there be a first catch? Or a "doesn't cascade" or something?
|
423
|
+
cascadeEvent: function(event) {
|
424
|
+
var formDiv = Ninja.tools.hiddenDiv()
|
425
|
+
forEach(this.stashedElements, function(element) {
|
426
|
+
var elem = jQuery(element)
|
427
|
+
elem.data("ninja-visited", true)
|
428
|
+
jQuery(formDiv).append(elem)
|
429
|
+
elem.trigger(event)
|
430
|
+
})
|
431
|
+
}
|
432
|
+
})
|
433
|
+
|
434
|
+
function BehaviorCollection() {
|
435
|
+
this.lexicalCount = 0
|
436
|
+
this.eventQueue = []
|
437
|
+
this.behaviors = {}
|
438
|
+
this.selectors = []
|
439
|
+
this.mutationTargets = []
|
440
|
+
return this
|
434
441
|
}
|
435
442
|
|
436
443
|
BehaviorCollection.prototype = {
|
@@ -469,7 +476,22 @@ Ninja = (function() {
|
|
469
476
|
this.behaviors[selector].push(behavior)
|
470
477
|
}
|
471
478
|
},
|
472
|
-
|
479
|
+
addMutationTargets: function(targets) {
|
480
|
+
this.mutationTargets = this.mutationTargets.concat(target)
|
481
|
+
},
|
482
|
+
fireMutationEvent: function() {
|
483
|
+
var targets = this.mutationTargets
|
484
|
+
if (targets.length > 0 ) {
|
485
|
+
for(var target = targets.shift();
|
486
|
+
targets.length > 0;
|
487
|
+
target = targets.shift()) {
|
488
|
+
jQuery(target).trigger("thisChangedDOM")
|
489
|
+
}
|
490
|
+
}
|
491
|
+
else {
|
492
|
+
Ninja.tools.getRootOfDocument().trigger("thisChangedDOM")
|
493
|
+
}
|
494
|
+
},
|
473
495
|
mutationEventTriggered: function(evnt){
|
474
496
|
if(this.eventQueue.length == 0){
|
475
497
|
log("mutation event - first")
|
@@ -485,8 +507,8 @@ Ninja = (function() {
|
|
485
507
|
var eventCovered = false
|
486
508
|
var uncovered = []
|
487
509
|
forEach(this.eventQueue, function(val) {
|
488
|
-
eventCovered = eventCovered ||
|
489
|
-
if (!(
|
510
|
+
eventCovered = eventCovered || jQuery.contains(val.target, evnt.target)
|
511
|
+
if (!(jQuery.contains(evnt.target, val.target))) {
|
490
512
|
uncovered.push(val)
|
491
513
|
}
|
492
514
|
})
|
@@ -548,10 +570,12 @@ Ninja = (function() {
|
|
548
570
|
}
|
549
571
|
}
|
550
572
|
)
|
551
|
-
|
573
|
+
jQuery(element).data("ninja-visited", true)
|
552
574
|
|
553
575
|
scribe.applyEventHandlers(element)
|
554
576
|
|
577
|
+
this.fireMutationEvent()
|
578
|
+
|
555
579
|
return element
|
556
580
|
},
|
557
581
|
collectBehaviors: function(element, collection, behaviors) {
|
@@ -574,12 +598,12 @@ Ninja = (function() {
|
|
574
598
|
apply: function(element, startBehaviors, selectorIndex) {
|
575
599
|
var applicableBehaviors = [], len = this.selectors.length
|
576
600
|
this.collectBehaviors(element, applicableBehaviors, startBehaviors)
|
577
|
-
if (
|
601
|
+
if (!jQuery(element).data("ninja-visited")) {
|
578
602
|
if(typeof selectorIndex == "undefined") {
|
579
603
|
selectorIndex = 0
|
580
604
|
}
|
581
605
|
for(var j = selectorIndex; j < len; j++) {
|
582
|
-
if(
|
606
|
+
if(jQuery(element).is(this.selectors[j])) {
|
583
607
|
this.collectBehaviors(element, applicableBehaviors, this.behaviors[this.selectors[j]])
|
584
608
|
}
|
585
609
|
}
|
@@ -592,9 +616,9 @@ Ninja = (function() {
|
|
592
616
|
var collection = this
|
593
617
|
|
594
618
|
//Sizzle?
|
595
|
-
|
619
|
+
jQuery(root).find(this.selectors[i]).each(
|
596
620
|
function(index, elem){
|
597
|
-
if (
|
621
|
+
if (!jQuery(elem).data("ninja-visited")) { //Pure optimization
|
598
622
|
collection.apply(elem, [], i)
|
599
623
|
}
|
600
624
|
}
|
@@ -629,7 +653,7 @@ Ninja = (function() {
|
|
629
653
|
Selectabehavior.prototype = {
|
630
654
|
choose: function(element) {
|
631
655
|
for(var selector in this.menu) {
|
632
|
-
if(
|
656
|
+
if(jQuery(element).is(selector)) {
|
633
657
|
return this.menu[selector].choose(element)
|
634
658
|
}
|
635
659
|
}
|
@@ -670,7 +694,7 @@ Ninja = (function() {
|
|
670
694
|
var context = this.inContext({})
|
671
695
|
|
672
696
|
elem = this.applyTransform(context, elem)
|
673
|
-
|
697
|
+
jQuery(elem).data("ninja-visited", true)
|
674
698
|
|
675
699
|
this.applyEventHandlers(context, elem)
|
676
700
|
|
@@ -701,7 +725,7 @@ Ninja = (function() {
|
|
701
725
|
applyEventHandlers: function(context, elem) {
|
702
726
|
for(var eventName in this.eventHandlers) {
|
703
727
|
var handler = this.eventHandlers[eventName]
|
704
|
-
|
728
|
+
jQuery(elem).bind(eventName, this.makeHandler.call(context, handler))
|
705
729
|
}
|
706
730
|
return elem
|
707
731
|
},
|
@@ -718,6 +742,7 @@ Ninja = (function() {
|
|
718
742
|
var stopDefault = true
|
719
743
|
var stopPropagate = true
|
720
744
|
var stopImmediate = false
|
745
|
+
var fireMutation = false
|
721
746
|
var config = this.eventHandlers[eventName]
|
722
747
|
|
723
748
|
if (typeof config == "function") {
|
@@ -728,15 +753,19 @@ Ninja = (function() {
|
|
728
753
|
config = config.slice(1,config.length)
|
729
754
|
var len = config.length
|
730
755
|
for(var i = 0; i < len; i++) {
|
731
|
-
if (config[i] == "
|
756
|
+
if (config[i] == "andDoDefault" || config[i] == "allowDefault") {
|
732
757
|
stopDefault = false
|
733
758
|
}
|
734
|
-
if (config[i] == "
|
759
|
+
if (config[i] == "allowPropagate" || config[i] == "dontStopPropagation") {
|
735
760
|
stopPropagate = false
|
736
761
|
}
|
737
|
-
|
762
|
+
//stopImmediatePropagation is a jQuery thing
|
763
|
+
if (config[i] == "andDoOthers") {
|
738
764
|
stopImmediate = false
|
739
765
|
}
|
766
|
+
if (config[i] == "changesDOM") {
|
767
|
+
fireMutation = true
|
768
|
+
}
|
740
769
|
}
|
741
770
|
}
|
742
771
|
var handler = function(eventRecord) {
|
@@ -758,13 +787,24 @@ Ninja = (function() {
|
|
758
787
|
eventRecord.stopImmediatePropagation()
|
759
788
|
})
|
760
789
|
}
|
790
|
+
if (fireMutation) {
|
791
|
+
handler = this.appendAction(handler, function(eventRecord) {
|
792
|
+
Ninja.tools.fireMutationEvent()
|
793
|
+
})
|
794
|
+
}
|
761
795
|
|
762
796
|
return handler
|
763
797
|
},
|
764
798
|
prependAction: function(handler, doWhat) {
|
765
799
|
return function(eventRecord) {
|
766
|
-
doWhat(eventRecord)
|
767
|
-
handler(eventRecord)
|
800
|
+
doWhat.call(this, eventRecord)
|
801
|
+
handler.call(this, eventRecord)
|
802
|
+
}
|
803
|
+
},
|
804
|
+
appendAction: function(handler, doWhat) {
|
805
|
+
return function(eventRecord) {
|
806
|
+
handler.call(this, eventRecord)
|
807
|
+
doWhat.call(this, eventRecord)
|
768
808
|
}
|
769
809
|
},
|
770
810
|
transform: function(elem){
|
@@ -818,15 +858,15 @@ Ninja = (function() {
|
|
818
858
|
priority: 10,
|
819
859
|
helpers: {
|
820
860
|
findOverlay: function(elem) {
|
821
|
-
return
|
861
|
+
return this.deriveElementsFrom(elem, configs.busyElement)
|
822
862
|
}
|
823
863
|
},
|
824
864
|
events: {
|
825
865
|
click: function(evnt) {
|
826
|
-
var overlay =
|
827
|
-
var submitter =
|
866
|
+
var overlay = this.busyOverlay(this.findOverlay(evnt.target))
|
867
|
+
var submitter = this.ajaxSubmitter()
|
828
868
|
submitter.action = evnt.target.href
|
829
|
-
submitter.method =
|
869
|
+
submitter.method = this.extractMethod(evnt.target)
|
830
870
|
|
831
871
|
submitter.onResponse = function(xhr, statusTxt) {
|
832
872
|
overlay.remove()
|
@@ -857,16 +897,16 @@ Ninja = (function() {
|
|
857
897
|
priority: 20,
|
858
898
|
helpers: {
|
859
899
|
findOverlay: function(elem) {
|
860
|
-
return
|
900
|
+
return this.deriveElementsFrom(elem, configs.busyElement)
|
861
901
|
}
|
862
902
|
},
|
863
903
|
events: {
|
864
904
|
submit: function(evnt) {
|
865
|
-
var overlay =
|
866
|
-
var submitter =
|
867
|
-
submitter.formData =
|
905
|
+
var overlay = this.busyOverlay(this.findOverlay(evnt.target))
|
906
|
+
var submitter = this.ajaxSubmitter()
|
907
|
+
submitter.formData = jQuery(evnt.target).serializeArray()
|
868
908
|
submitter.action = evnt.target.action
|
869
|
-
submitter.method =
|
909
|
+
submitter.method = this.extractMethod(evnt.target, submitter.formData)
|
870
910
|
|
871
911
|
submitter.onResponse = function(xhr, statusTxt) {
|
872
912
|
overlay.remove()
|
@@ -886,7 +926,7 @@ Ninja = (function() {
|
|
886
926
|
//busy overlay - by default we overlay the element itself
|
887
927
|
//
|
888
928
|
//this.becomesAjaxLink({
|
889
|
-
// busyElement: function(elem) {
|
929
|
+
// busyElement: function(elem) { jQuery("#user-notification") }
|
890
930
|
//})
|
891
931
|
becomesAjaxLink: function(configs) {
|
892
932
|
if(!(configs instanceof Object)) {
|
@@ -917,11 +957,11 @@ Ninja = (function() {
|
|
917
957
|
priority: 30,
|
918
958
|
transform: function(form){
|
919
959
|
var linkText
|
920
|
-
if ((images =
|
960
|
+
if ((images = jQuery('input[type=image]', form)).size() > 0){
|
921
961
|
image = images[0]
|
922
962
|
linkText = "<img src='" + image.src + "' alt='" + image.alt +"'";
|
923
963
|
}
|
924
|
-
else if((submits =
|
964
|
+
else if((submits = jQuery('input[type=submit]', form)).size() > 0) {
|
925
965
|
submit = submits[0]
|
926
966
|
if(submits.size() > 1) {
|
927
967
|
log("Multiple submits. Using: " + submit)
|
@@ -932,9 +972,9 @@ Ninja = (function() {
|
|
932
972
|
log("Couldn't find a submit input in form");
|
933
973
|
}
|
934
974
|
|
935
|
-
var link =
|
936
|
-
|
937
|
-
this.stash(
|
975
|
+
var link = jQuery("<a rel='nofollow' href='#'>" + linkText + "</a>")
|
976
|
+
this.copyAttributes(form, link, configs.retainAttributes)
|
977
|
+
this.stash(jQuery(form).replaceWith(link))
|
938
978
|
return link
|
939
979
|
},
|
940
980
|
events: {
|
@@ -955,26 +995,23 @@ Ninja = (function() {
|
|
955
995
|
//{ lifetime: 10000, diesFor: 600 }
|
956
996
|
|
957
997
|
decays: function(configs) {
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
}
|
963
|
-
|
964
|
-
if(typeof configs.diesFor == "undefined") {
|
965
|
-
configs.diesFor = 600
|
966
|
-
}
|
998
|
+
configs = Ninja.tools.ensureDefaults(configs, {
|
999
|
+
lifetime: 10000,
|
1000
|
+
diesFor: 600
|
1001
|
+
})
|
967
1002
|
|
968
1003
|
return new ninja.does({
|
969
1004
|
priority: 100,
|
970
1005
|
transform: function(elem) {
|
971
|
-
|
972
|
-
|
1006
|
+
jQuery(elem).delay(configs.lifetime).slideUp(configs.diesFor, function(){
|
1007
|
+
jQuery(elem).remove()
|
1008
|
+
Ninja.tools.fireMutationEvent()
|
1009
|
+
})
|
973
1010
|
},
|
974
1011
|
events: {
|
975
|
-
click: function(
|
976
|
-
|
977
|
-
}
|
1012
|
+
click: [function(event) {
|
1013
|
+
jQuery(this.element).remove();
|
1014
|
+
}, "changesDOM"]
|
978
1015
|
}
|
979
1016
|
})
|
980
1017
|
}
|
@@ -0,0 +1,132 @@
|
|
1
|
+
jQuery(function ($) {
|
2
|
+
var csrf_token = $('meta[name=csrf-token]').attr('content'),
|
3
|
+
csrf_param = $('meta[name=csrf-param]').attr('content');
|
4
|
+
|
5
|
+
$.fn.extend({
|
6
|
+
/**
|
7
|
+
* Triggers a custom event on an element and returns the event result
|
8
|
+
* this is used to get around not being able to ensure callbacks are placed
|
9
|
+
* at the end of the chain.
|
10
|
+
*
|
11
|
+
* TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
|
12
|
+
* own events and placing ourselves at the end of the chain.
|
13
|
+
*/
|
14
|
+
triggerAndReturn: function (name, data) {
|
15
|
+
var event = new $.Event(name);
|
16
|
+
this.trigger(event, data);
|
17
|
+
|
18
|
+
return event.result !== false;
|
19
|
+
},
|
20
|
+
|
21
|
+
/**
|
22
|
+
* Handles execution of remote calls firing overridable events along the way
|
23
|
+
*/
|
24
|
+
callRemote: function () {
|
25
|
+
var el = this,
|
26
|
+
method = el.attr('method') || el.attr('data-method') || 'GET',
|
27
|
+
url = el.attr('action') || el.attr('href'),
|
28
|
+
dataType = el.attr('data-type') || 'script';
|
29
|
+
|
30
|
+
if (url === undefined) {
|
31
|
+
throw "No URL specified for remote call (action or href must be present).";
|
32
|
+
} else {
|
33
|
+
if (el.triggerAndReturn('ajax:before')) {
|
34
|
+
var data = el.is('form') ? el.serializeArray() : [];
|
35
|
+
$.ajax({
|
36
|
+
url: url,
|
37
|
+
data: data,
|
38
|
+
dataType: dataType,
|
39
|
+
type: method.toUpperCase(),
|
40
|
+
beforeSend: function (xhr) {
|
41
|
+
el.trigger('ajax:loading', xhr);
|
42
|
+
},
|
43
|
+
success: function (data, status, xhr) {
|
44
|
+
el.trigger('ajax:success', [data, status, xhr]);
|
45
|
+
},
|
46
|
+
complete: function (xhr) {
|
47
|
+
el.trigger('ajax:complete', xhr);
|
48
|
+
},
|
49
|
+
error: function (xhr, status, error) {
|
50
|
+
el.trigger('ajax:failure', [xhr, status, error]);
|
51
|
+
}
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
el.trigger('ajax:after');
|
56
|
+
}
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
/**
|
61
|
+
* confirmation handler
|
62
|
+
*/
|
63
|
+
$('a[data-confirm],input[data-confirm]').live('click', function () {
|
64
|
+
var el = $(this);
|
65
|
+
if (el.triggerAndReturn('confirm')) {
|
66
|
+
if (!confirm(el.attr('data-confirm'))) {
|
67
|
+
return false;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
});
|
71
|
+
|
72
|
+
|
73
|
+
/**
|
74
|
+
* remote handlers
|
75
|
+
*/
|
76
|
+
$('form[data-remote]').live('submit', function (e) {
|
77
|
+
$(this).callRemote();
|
78
|
+
e.preventDefault();
|
79
|
+
});
|
80
|
+
|
81
|
+
$('a[data-remote],input[data-remote]').live('click', function (e) {
|
82
|
+
$(this).callRemote();
|
83
|
+
e.preventDefault();
|
84
|
+
});
|
85
|
+
|
86
|
+
$('a[data-method]:not([data-remote])').live('click', function (e){
|
87
|
+
var link = $(this),
|
88
|
+
href = link.attr('href'),
|
89
|
+
method = link.attr('data-method'),
|
90
|
+
form = $('<form method="post" action="'+href+'"></form>'),
|
91
|
+
metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
|
92
|
+
|
93
|
+
if (csrf_param != null && csrf_token != null) {
|
94
|
+
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
|
95
|
+
}
|
96
|
+
|
97
|
+
form.hide()
|
98
|
+
.append(metadata_input)
|
99
|
+
.appendTo('body');
|
100
|
+
|
101
|
+
e.preventDefault();
|
102
|
+
form.submit();
|
103
|
+
});
|
104
|
+
|
105
|
+
/**
|
106
|
+
* disable-with handlers
|
107
|
+
*/
|
108
|
+
var disable_with_input_selector = 'input[data-disable-with]';
|
109
|
+
var disable_with_form_remote_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
|
110
|
+
var disable_with_form_not_remote_selector = 'form:not([data-remote]):has(' + disable_with_input_selector + ')';
|
111
|
+
|
112
|
+
var disable_with_input_function = function () {
|
113
|
+
$(this).find(disable_with_input_selector).each(function () {
|
114
|
+
var input = $(this);
|
115
|
+
input.data('enable-with', input.val())
|
116
|
+
.attr('value', input.attr('data-disable-with'))
|
117
|
+
.attr('disabled', 'disabled');
|
118
|
+
});
|
119
|
+
};
|
120
|
+
|
121
|
+
$(disable_with_form_remote_selector).live('ajax:before', disable_with_input_function);
|
122
|
+
$(disable_with_form_not_remote_selector).live('submit', disable_with_input_function);
|
123
|
+
|
124
|
+
$(disable_with_form_remote_selector).live('ajax:complete', function () {
|
125
|
+
$(this).find(disable_with_input_selector).each(function () {
|
126
|
+
var input = $(this);
|
127
|
+
input.removeAttr('disabled')
|
128
|
+
.val(input.data('enable-with'));
|
129
|
+
});
|
130
|
+
});
|
131
|
+
|
132
|
+
});
|
data/lib/mizugumo_link_helper.rb
CHANGED
@@ -43,11 +43,14 @@ module MizugumoLinkHelper
|
|
43
43
|
# debugger
|
44
44
|
method = html_options[:method]
|
45
45
|
|
46
|
+
# debugger
|
47
|
+
|
46
48
|
cssclass = [ 'mizugumo_graceful_form' ]
|
47
49
|
cssclass << html_options[:class] unless html_options[:class].blank?
|
48
50
|
html_options = convert_options_to_data_attributes(options, html_options)
|
49
51
|
html_options.merge!({:action => action, :method => :post, :title => title, :class => cssclass})
|
50
52
|
html_options.delete('rel')
|
53
|
+
html_options.delete('class')
|
51
54
|
|
52
55
|
content_tag(:form, html_options) do
|
53
56
|
hidden_field_tag("_method", method) +
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mizugumo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Evan Dorn
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-02-03 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -79,7 +79,7 @@ dependencies:
|
|
79
79
|
version: "0"
|
80
80
|
type: :development
|
81
81
|
version_requirements: *id004
|
82
|
-
description: Seamless UJS for Rails using NinjaScript
|
82
|
+
description: "Seamless UJS for Rails using NinjaScript.\n Get RESTFul delete links that work without JavaScript and AJAXy\n behavior that degrades gracefully right out of your scaffold!\n "
|
83
83
|
email: evan@lrdesign.com
|
84
84
|
executables: []
|
85
85
|
|
@@ -100,6 +100,7 @@ files:
|
|
100
100
|
- lib/generators/mizugumo/install/templates/images/ui/spinner.gif
|
101
101
|
- lib/generators/mizugumo/install/templates/javascripts/jquery-1.4.2.js
|
102
102
|
- lib/generators/mizugumo/install/templates/javascripts/jquery.ninja_script.js
|
103
|
+
- lib/generators/mizugumo/install/templates/javascripts/rails.js
|
103
104
|
- lib/generators/mizugumo/install/templates/stylesheets/mizugumo.css
|
104
105
|
- lib/generators/mizugumo/install/templates/stylesheets/sass/mizugumo.sass
|
105
106
|
- lib/generators/rails/mizugumo/erb_generator.rb
|
@@ -126,9 +127,12 @@ files:
|
|
126
127
|
- lib/generators/rails/mizugumo/view_generator.rb
|
127
128
|
- lib/mizugumo.rb
|
128
129
|
- lib/mizugumo_link_helper.rb
|
130
|
+
- doc/making_generators.txt
|
131
|
+
- doc/NAME.haml
|
132
|
+
- doc/PURPOSE.haml
|
129
133
|
- spec/spec_helper.rb
|
130
134
|
has_rdoc: true
|
131
|
-
homepage: http://github.com/
|
135
|
+
homepage: http://github.com/LRDesign/mizugumo
|
132
136
|
licenses:
|
133
137
|
- MIT
|
134
138
|
post_install_message:
|