btakita-jelly 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +3 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README.markdown +346 -0
  4. data/Rakefile +39 -0
  5. data/VERSION.yml +5 -0
  6. data/generators/jelly/USAGE +11 -0
  7. data/generators/jelly/jelly_generator.rb +12 -0
  8. data/generators/jelly/templates/javascripts/ajax_with_jelly.js +33 -0
  9. data/generators/jelly/templates/javascripts/jelly.js +97 -0
  10. data/generators/jelly/templates/javascripts/jquery/jquery-1.3.2.js +4376 -0
  11. data/generators/jelly/templates/javascripts/jquery/jquery.protify-0.3.js +345 -0
  12. data/install.rb +1 -0
  13. data/jelly.gemspec +77 -0
  14. data/lib/jelly.rb +16 -0
  15. data/lib/jelly/jelly_controller.rb +23 -0
  16. data/lib/jelly/jelly_helper.rb +45 -0
  17. data/spec/controllers/jelly_controller_spec.rb +118 -0
  18. data/spec/helpers/jelly_helper_spec.rb +54 -0
  19. data/spec/rails_root/app/controllers/application_controller.rb +10 -0
  20. data/spec/rails_root/app/helpers/application_helper.rb +3 -0
  21. data/spec/rails_root/config/boot.rb +110 -0
  22. data/spec/rails_root/config/environment.rb +41 -0
  23. data/spec/rails_root/config/environments/development.rb +17 -0
  24. data/spec/rails_root/config/environments/production.rb +28 -0
  25. data/spec/rails_root/config/environments/test.rb +28 -0
  26. data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
  27. data/spec/rails_root/config/initializers/inflections.rb +10 -0
  28. data/spec/rails_root/config/initializers/mime_types.rb +5 -0
  29. data/spec/rails_root/config/initializers/new_rails_defaults.rb +19 -0
  30. data/spec/rails_root/config/initializers/session_store.rb +15 -0
  31. data/spec/rails_root/config/routes.rb +43 -0
  32. data/spec/rails_root/test/performance/browsing_test.rb +9 -0
  33. data/spec/rails_root/test/test_helper.rb +38 -0
  34. data/spec/spec_helper.rb +38 -0
  35. data/spec/spec_suite.rb +3 -0
  36. data/tasks/jelly_tasks.rake +4 -0
  37. data/uninstall.rb +1 -0
  38. metadata +99 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .idea
2
+ *.svn
3
+ pkg
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009 Pivotal Labs, Inc.
2
+ with contributions by: Brian Takita, Nate Clark, Eric Metens
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,346 @@
1
+ Jelly
2
+ =====
3
+
4
+ What is Jelly?
5
+ --------------
6
+ Jelly is an unobtrusive Javascript framework for [jQuery](http://jquery.com) and [Rails](http://rubyonrails.org).
7
+ It provides a set of conventions and tools that help you organize your AJAX and client-side code,
8
+ while keeping Javascript out of your views and markup. Jelly is the glue between your Rails controllers
9
+ and jQuery events.
10
+
11
+ Jelly encourages and enables unit testing your Javascript code. Using a Javascript testing framework such as [Jasmine](http://github.com/pivotal/jasmine)
12
+ or [Screw Unit](http://github.com/nathansobo/screw-unit), Jelly allows you to test AJAX and client-side
13
+ events independently from your Rails app.
14
+
15
+ Key Benefits
16
+ ------------
17
+ * [Unobtrusive Javascript](http://en.wikipedia.org/wiki/Unobtrusive_JavaScript). Your Javascript code remains completely
18
+ separate from your markup.
19
+ * [Test Driven Development](http://en.wikipedia.org/wiki/Test-driven_development). Jelly blends well with the Javascript testing framework
20
+ [Jasmine](http://github.com/pivotal/jasmine) and allows you to test-drive your ajaxy and client-side code.
21
+ * Familiar conventions. Jelly follows the conventions of Ruby on Rails, making it simple for developers to organize and keep track of their Javascript code.
22
+
23
+ What Jelly is NOT
24
+ -----------------
25
+ **Jelly is NOT a Javascript generator.** With Jelly, you're writing pure Javascript to define your AJAX browser events. Jelly simply
26
+ provides a set of Javascript functions to make interacting with Rails easier. It's nothing like RJS.
27
+
28
+ **Jelly is NOT a Javascript framework.** Jelly is designed to be used with jQuery and jQuery's event-based
29
+ AJAX framework. Jelly also supports the popular [jQuery ajaxForm](http://malsup.com/jquery/form/) plugin.
30
+
31
+ Requirements
32
+ ------------
33
+ * Rails 2.3.x
34
+ * jQuery 1.3.x
35
+
36
+ Installation
37
+ ------------
38
+
39
+ Jelly is now available as a gem on on [RubyForge](http://rubyforge.org/projects/pivotalrb/):
40
+
41
+ sudo gem install jelly
42
+
43
+ Then, install the required Javascript files to your <code>public/javascripts</code> directory by running the Jelly generator:
44
+
45
+ script/generate jelly
46
+
47
+ Getting Started
48
+ --------------------------------
49
+
50
+ Be sure to require <code>jelly</code> when your application loads. This can be done in your `environment.rb` in the `Rails::Initializer.run` block:
51
+
52
+ config.gem 'jelly'
53
+
54
+ Then, in your layouts, add the following to the `<head>` section:
55
+
56
+ <%= javascript_include_tag :jelly, *application_jelly_files %>
57
+ <%= spread_jelly %>
58
+
59
+ The `javascript_include_tag` line will include the required Javascript libraries for jelly. The `:jelly` javascript
60
+ expansion includes the latest version of jQuery. If you already have jQuery included in the page, use the `:only_jelly`
61
+ expansion instead
62
+
63
+ The `spread_jelly` line activates the events that you have defined on the current page.
64
+
65
+ Basic Usage
66
+ -------------
67
+
68
+ Jelly maps page-specific Javascript functions to Rails Actions and Controllers. For example: StoriesController#index will
69
+ activate the `index` function in the `Fun` Jelly object. Jelly uses jQuery's `$(document).ready()` to execute the
70
+ page-specifc function when the page has loaded. Let's look at some code:
71
+
72
+ In public/javascripts/pages/stories.js, we create a simple Jelly file:
73
+
74
+ Jelly.add("Stories", {
75
+
76
+ index: function() {
77
+ $('a.clickme').click(function() {
78
+ alert('Hello world!');
79
+ });
80
+ }
81
+
82
+ });
83
+
84
+ Jelly will automatically execute the `index` function when the Rails app runs the `StoriesController#index` action. Lets
85
+ continue the example by adding more Javascript functions that map to the `new` and `show` Rails actions. We can also
86
+ specify an `all` function, which will be executed on all actions in the `StoriesController`.
87
+
88
+ Jelly.add("Stories", {
89
+
90
+ index: function() {
91
+ $('a.clickme').click(function() {
92
+ alert('Hello world!');
93
+ });
94
+ },
95
+
96
+ 'new': function() {
97
+ $('#mydiv').html('<span>Hello World</span>');
98
+ },
99
+
100
+ show : function() {},
101
+
102
+ all: function() {
103
+ $('#hidden_stuff').show();
104
+ }
105
+
106
+ });
107
+
108
+ Notice the slightly different syntax for `new`. This is because `new` is a reserved word in Javascript.
109
+ Create a separate file in `public/javascripts/pages` for each of your controllers as you use Jelly throughout your application.
110
+
111
+ Common Components
112
+ -----------------
113
+
114
+ Often you will want to mix common Javascript components on many pages throughout your application, not just in the namespace
115
+ of a single Controller. Jelly Components allow you to organize common Javascript code, and invoke it on arbitrary pages
116
+ within your application.
117
+
118
+ Jelly Components are simply Javascript classes with (at least) an `init` function. Here's an example of a `SearchBox` component that
119
+ activates an autocompleter on a search box on every page.
120
+
121
+ in public/javascripts/components/search_box.js:
122
+
123
+ SearchBox = {
124
+ init: function(){
125
+ $("#search_box").autocompleter({
126
+ url : '/search'
127
+ });
128
+ }
129
+ };
130
+
131
+ To attach the SearchBox component to the page and automatically call the `init` function when the page is ready, we use the `attach_javascript_component`
132
+ method in our view. This can be done either in your layout (for components to attach to all pages), or in your view using
133
+ `content_for`.
134
+
135
+ in the `<head>` tag of the layout:
136
+
137
+ <%= attach_javascript_component('SearchBox') %>
138
+
139
+ or in a view:
140
+
141
+ <% content_for :javascript do -%>
142
+ <%= attach_javascript_component('SearchBox') %>
143
+ <% end -%>
144
+
145
+ Components always get initialized **after** the page-specific Javascript functions.
146
+
147
+ AJAX With Jelly
148
+ ---------------
149
+
150
+ Jelly adds an `$.ajaxWithJelly()` function to the jQuery namespace which is a simple wrapper for jQuery's `$.ajax()`.
151
+ When you use `$.ajaxWithJelly()` to create an ajax event, Jelly automatically adds an onSuccess handler to your ajax
152
+ call that invokes the Jelly framework after receiving the ajax response.
153
+
154
+ Jelly's convention relies on the Controller to specify the javascript callback after an ajax request. We can invoke Jelly
155
+ in response to a javascript request with the `jelly_callback` method.
156
+
157
+ This example assumes that you have working knowledge of jQuery's `$.ajax()` function. If not, [read up on it here](http://docs.jquery.com/Ajax).
158
+
159
+ ### Simple AJAX example with `$.ajaxWithJelly()` and `jelly_callback`
160
+
161
+ The view, new.html.erb:
162
+
163
+ <a href="#" id="create_story_link">create story</a>
164
+
165
+ The controller, stories_controller.rb
166
+
167
+ class StoriesController < ApplicationController
168
+ def new
169
+ end
170
+
171
+ def create
172
+ Story.create!(params[:story])
173
+ respond_to do |format|
174
+ format.html
175
+ format.js { jelly_callback }
176
+ end
177
+ end
178
+ end
179
+
180
+ The javascript, pages/stories.js:
181
+
182
+ Jelly.add("Stories", {
183
+
184
+ new: function() {
185
+ $("#create_story_link").click(function() {
186
+ $.ajaxWithJelly({
187
+ url: "/stories",
188
+ data: {
189
+ name : 'Untitled Story',
190
+ }
191
+ });
192
+ });
193
+ },
194
+
195
+ on_create: function() {
196
+ alert('Your story has been created!');
197
+ }
198
+ });
199
+
200
+ The example above attaches an ajax event to the "create story" link, and when clicked, jQuery will fire a ajax POST request to
201
+ the create action of our controller. The controller then responds with `jelly_callback`, and by default invokes the
202
+ javascript function named `on_create` in the Stories javascript file.
203
+
204
+ ### Passing parameters to the Jelly callback target
205
+
206
+ If we wanted to make the creation of the story a bit more interesting, we can send back a html fragment of the
207
+ new story that has been created, and pass it as a parameter to `on_create` so it can be added to the page. Let's see how that might look:
208
+
209
+ The view, new.html.erb:
210
+
211
+ <a href="#" id="create_story_link">create story</a>
212
+ <ul id="stories">
213
+ <li>First Story</li>
214
+ </ul>
215
+
216
+ The controller, stories_controller.rb
217
+
218
+ class StoriesController < ApplicationController
219
+ def new
220
+ end
221
+
222
+ def create
223
+ Story.create!(params[:story])
224
+ respond_to do |format|
225
+ format.html
226
+ format.js do
227
+ jelly_callback do
228
+ render :partial => 'story_list_item'
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+ The javascript, pages/stories.js:
236
+
237
+ Jelly.add("Stories", {
238
+
239
+ new: function() {
240
+ $("#create_story_link").click(function() {
241
+ $.ajaxWithJelly({
242
+ url: "/stories",
243
+ data: {
244
+ name : 'Untitled Story',
245
+ }
246
+ });
247
+ });
248
+ },
249
+
250
+ on_create: function(storyListItemHtml) {
251
+ $("#stories").append(storyListItemHtml);
252
+ }
253
+ });
254
+
255
+ The `jelly_callback` function accepts a block which is evaluated in the context of the view layer, which allows you to
256
+ render partials and use Rails Helpers as you normally would. You can pass as many parameters as you want to the javascript
257
+ callback by passing an array to the `jelly_callback` block:
258
+
259
+ ### Passing multiple parameters to the Jelly callback target
260
+
261
+ in the controller, stories_controller.rb:
262
+
263
+ def create
264
+ @story = Story.create!(params[:story])
265
+ respond_to do |format|
266
+ format.html
267
+ format.js do
268
+ jelly_callback do
269
+ [ render(:partial => 'story_list_item'), @story.id, "Nice looking story, smart guy" ]
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ in the javascript, pages/stories.js:
276
+
277
+ on_create: function(storyListItemHtml, storyId, message) {
278
+ $(storyListItemHtml).attr('id', storyId).appendTo($("#stories"));
279
+ alert(message);
280
+ },
281
+
282
+ ### Specifying custom callback functions in jelly_callback
283
+
284
+ As we have seen above, by default, `jelly_callback` invokes the javascript function by prepending `on_` to the Rails
285
+ action name. The `jelly_callback` method can take an optional parameter for the name of the callback to allow more fine-grained
286
+ client-side behaviors depending on the server-side response.
287
+
288
+ in the controller, stories_controller.rb
289
+
290
+ def create
291
+ begin
292
+ Story.create!(params[:story])
293
+ respond_to do |format|
294
+ format.html
295
+ format.js do
296
+ jelly_callback('successful_create') do
297
+ render :partial => 'story_list_item'
298
+ end
299
+ end
300
+ end
301
+ rescue
302
+ respond_to do |format|
303
+ format.html
304
+ format.js do
305
+ jelly_callback('failed_create')
306
+ end
307
+ end
308
+ end
309
+ end
310
+
311
+ in the javascript, pages/stories.js:
312
+
313
+ on_successful_create: function(storyListItemHtml) {
314
+ $("#stories").append(storyListItemHtml);
315
+ },
316
+
317
+ on_failed_create: function() {
318
+ alert('Oops, there was a problem creating your story!);
319
+ }
320
+
321
+ ### Callbacks to Jelly Components
322
+
323
+ By default, ajax callbacks functions are scoped to the current Jelly page. But if you want, you can also direct ajax
324
+ callbacks to functions on Jelly components or other Javascript objects in your application. To
325
+ do this, send an `:on` paremeter to `jelly_callback`, for example.
326
+
327
+ in the controller:
328
+
329
+ respond_to do |format|
330
+ format.js do
331
+ jelly_callback('successful_create', :on => 'CommonHandler') do
332
+ render :partial => 'story_list_item'
333
+ end
334
+ end
335
+ end
336
+
337
+ This will call `CommonHandler.on_successful_create()` with the response.
338
+
339
+ Jelly Development
340
+ -----------------
341
+
342
+ Track Jelly's development roadmap on [Jelly's Pivotal Tracker project](http://www.pivotaltracker.com/projects/30454)
343
+
344
+ To run ruby tests, run `rake spec`.
345
+
346
+ To run Javascript tests, open `jelly/spec/jasmine_runner.html` in Firefox or Safari.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ require 'spec/version'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run specs'
6
+ task :default => :spec
7
+
8
+ desc 'Test the jelly plugin with Rspec.'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'spec'
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the jelly plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'Jelly.'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = ENV["GEM_PREFIX"] ? "#{ENV["GEM_PREFIX"]}-jelly" : "jelly"
29
+ gemspec.summary = "a sweet unobtrusive javascript framework for jQuery and Rails"
30
+ gemspec.description = "Jelly provides a set of tools and conventions for creating rich ajax/javascript web applications with jQuery and Ruby on Rails."
31
+ gemspec.email = "opensource@pivotallabs.com"
32
+ gemspec.homepage = "http://github.com/pivotal/jelly"
33
+ gemspec.authors = ["Pivotal Labs, Inc"]
34
+ gemspec.files.exclude 'spec/**/*'
35
+ gemspec.add_dependency('rails', '>= 2.3.0')
36
+ end
37
+ rescue LoadError
38
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
39
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :build:
3
+ :patch: 0
4
+ :major: 0
5
+ :minor: 6
@@ -0,0 +1,11 @@
1
+ Description:
2
+ Creates 'jelly.js' and dependent jQuery libraries
3
+
4
+ Example:
5
+ ./script/generate jelly
6
+
7
+ This will create:
8
+ public/javascripts/jelly.js
9
+ public/javascripts/jquery-1.3.2.js
10
+ public/javascripts/jquery.protify-0.3.js
11
+
@@ -0,0 +1,12 @@
1
+ class JellyGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.file 'javascripts/jelly.js', "public/javascripts/jelly.js"
5
+ m.file 'javascripts/ajax_with_jelly.js', "public/javascripts/ajax_with_jelly.js"
6
+ m.directory('public/javascripts/jquery')
7
+ m.file 'javascripts/jquery/jquery-1.3.2.js', "public/javascripts/jquery/jquery-1.3.2.js"
8
+ m.file 'javascripts/jquery/jquery.protify-0.3.js', "public/javascripts/jquery/jquery.protify-0.3.js"
9
+ m.directory('public/javascripts/pages')
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ if(!window.Jelly) Jelly = new Object();
2
+
3
+ (Jelly.defineAjaxWithJellyFunctions = function($) {
4
+ $.ajaxWithJelly = function(params) {
5
+ $.ajax($.ajaxWithJelly.params(params));
6
+ };
7
+
8
+ if ($.fn.ajaxForm) {
9
+ $.fn.ajaxFormWithJelly = function(params) {
10
+ this.ajaxForm($.ajaxWithJelly.params(params));
11
+ };
12
+ }
13
+
14
+ $.ajaxWithJelly.params = function(otherParams) {
15
+ otherParams = otherParams || {};
16
+
17
+ if (otherParams.type && otherParams.type != "GET") {
18
+ otherParams['data'] = $.extend(otherParams['data'], {
19
+ authenticity_token: window._token
20
+ });
21
+ }
22
+ return $.extend({
23
+ dataType: 'json',
24
+ cache: false,
25
+ success : $.ajaxWithJelly.onSuccess
26
+ }, otherParams);
27
+ };
28
+
29
+ $.ajaxWithJelly.onSuccess = function(json) {
30
+ Jelly.notifyObservers(json);
31
+ return true;
32
+ };
33
+ })(jQuery);