honkster-jelly 0.7.7 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 7
3
- :patch: 7
2
+ :minor: 8
3
+ :patch: 1
4
4
  :major: 0
@@ -19,12 +19,13 @@ if(!window.Jelly) Jelly = new Object();
19
19
  authenticity_token: window._token
20
20
  });
21
21
  }
22
+ var observers = otherParams.observers || Jelly.observers;
22
23
  return $.extend({
23
24
  dataType: 'json',
24
25
  cache: false,
25
- success : $.ajaxWithJelly.onSuccess
26
+ success : function(callbacks) {
27
+ Jelly.notifyObservers.call(observers, callbacks);
28
+ }
26
29
  }, otherParams);
27
30
  };
28
-
29
- $.ajaxWithJelly.onSuccess = Jelly.notifyObservers.bind(Jelly);
30
31
  })(jQuery);
@@ -2,7 +2,7 @@
2
2
  * Jelly. a sweet unobtrusive javascript framework
3
3
  * for jQuery and Rails
4
4
  *
5
- * version 0.7.7
5
+ * version 0.8.1
6
6
  *
7
7
  * Copyright (c) 2009 Pivotal Labs
8
8
  * Licensed under the MIT license.
@@ -21,8 +21,9 @@ if (!Function.prototype.bind) {
21
21
  }
22
22
  }
23
23
  Jelly.init = function() {
24
- this.components = [];
25
24
  this.observers = [];
25
+ this.observers.pending = [];
26
+ this.attach = this.Observers.attach;
26
27
  this.notifyObservers = this.Observers.notify;
27
28
  this.Components.initCalled = false;
28
29
  this.Pages.init();
@@ -32,65 +33,79 @@ Jelly.init = function() {
32
33
  });
33
34
  };
34
35
 
35
- Jelly.attach = function() {
36
- for (var i = 0; i < arguments.length; i++) {
37
- var definition = arguments[i];
38
- var component = (typeof definition.component == "string") ?
39
- eval(definition.component) :
40
- definition.component;
41
- var evaluatedDefinition = {
42
- component: component,
43
- arguments: definition.arguments
44
- };
45
- this.components.push(evaluatedDefinition);
46
- if (Jelly.Components.initCalled) {
47
- Jelly.Components.initComponentFromDefinition(evaluatedDefinition);
36
+ Jelly.Components = {
37
+ init: function() {
38
+ for (var i = 0; i < Jelly.observers.pending.length; i++) {
39
+ Jelly.Observers.initPending.call(Jelly.observers, Jelly.observers.pending[i]);
48
40
  }
41
+ this.initCalled = true;
49
42
  }
50
43
  };
51
44
 
52
- Jelly.Components = {
53
- init: function() {
54
- for (var i = 0; i < Jelly.components.length; i++) {
55
- this.initComponentFromDefinition(Jelly.components[i]);
45
+ Jelly.Observers = {
46
+ attach: function() {
47
+ if (this == Jelly) {
48
+ return Jelly.Observers.attach.apply(this.observers, arguments);
49
+ }
50
+ this.pending = this.pending || [];
51
+ for (var i = 0; i < arguments.length; i++) {
52
+ var definition = arguments[i];
53
+ var component = (typeof definition.component == "string") ?
54
+ eval(definition.component) :
55
+ definition.component;
56
+ var evaluatedDefinition = {
57
+ component: component,
58
+ arguments: definition.arguments
59
+ };
60
+ this.pending.push(evaluatedDefinition);
61
+ if (Jelly.Components.initCalled) {
62
+ Jelly.Observers.initPending.call(this, evaluatedDefinition);
63
+ }
56
64
  }
57
- this.initCalled = true;
58
65
  },
59
- initComponentFromDefinition: function(definition) {
66
+
67
+ initPending: function(definition) {
60
68
  var observer;
61
69
  if (definition.component.init) {
62
70
  observer = definition.component.init.apply(definition.component, definition.arguments);
63
71
  }
64
- Jelly.observers.push(observer ? observer : definition.component);
65
- }
66
- };
72
+ this.push(observer ? observer : definition.component);
73
+ },
67
74
 
68
- Jelly.Observers = {
69
- notify: function(params) {
70
- if (this == Jelly) return Jelly.Observers.notify.call(this.observers, params);
71
- var observers = this.slice(0);
75
+ notify: function(callbacks) {
76
+ if (this == Jelly) {
77
+ return Jelly.Observers.notify.apply(this.observers, arguments);
78
+ }
79
+ if (!$.isArray(callbacks)) {
80
+ callbacks = [callbacks];
81
+ }
72
82
 
73
- // Deprecate 'on' in favor of making each page action a Component.
74
- if (params.on) {
75
- var additionalObserver = eval(params.on);
76
- if (observers.indexOf(additionalObserver) == -1) {
77
- observers.push(additionalObserver);
83
+ var observers = this.slice(0);
84
+ for (var i = 0; i < callbacks.length; i++) {
85
+ var callback = callbacks[i];
86
+
87
+ // Deprecate 'on' in favor of making each page action a Component.
88
+ if (callback.on) {
89
+ var additionalObserver = eval(callback.on);
90
+ if (observers.indexOf(additionalObserver) == -1) {
91
+ observers.push(additionalObserver);
92
+ }
78
93
  }
79
- }
80
94
 
81
- for (var i = 0; i < observers.length; i++) {
82
- var observer = observers[i];
83
- if (observer[params.method]) {
84
- if (observer.detach && observer.detach()) {
85
- Jelly.Observers.garbageCollectObserver.call(this, observer);
86
- } else {
87
- observer[params.method].apply(observer, params.arguments);
95
+ for (var j = 0; j < observers.length; j++) {
96
+ var observer = observers[j];
97
+ if (observer[callback.method]) {
98
+ if (observer.detach && observer.detach()) {
99
+ Jelly.Observers.garbageCollectObserver.call(this, observer);
100
+ } else {
101
+ observer[callback.method].apply(observer, callback.arguments);
102
+ }
88
103
  }
89
104
  }
90
- }
91
105
 
92
- if (params.attach) {
93
- Jelly.attach.apply(Jelly, params.attach);
106
+ if (callback.attach) {
107
+ Jelly.Observers.attach.apply(this, callback.attach);
108
+ }
94
109
  }
95
110
  },
96
111
 
data/jelly.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{jelly}
8
- s.version = "0.7.7"
8
+ s.version = "0.8.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Pivotal Labs, Inc"]
12
- s.date = %q{2009-12-28}
12
+ s.date = %q{2009-12-29}
13
13
  s.description = %q{Jelly provides a set of tools and conventions for creating rich ajax/javascript web applications with jQuery and Ruby on Rails.}
14
14
  s.email = %q{opensource@pivotallabs.com}
15
15
  s.extra_rdoc_files = [
@@ -3,6 +3,14 @@ module JellyController
3
3
  include Jelly::Common
4
4
 
5
5
  def jelly_callback(callback_base_name = @action_name, options = {}, &block)
6
+ raw_jelly_callback(options) do
7
+ arguments = block.try(:call) || []
8
+ jelly_callback_hash("on_#{callback_base_name}", *arguments).merge(options)
9
+ end
10
+ end
11
+
12
+ def raw_jelly_callback(options={}, &block)
13
+ options.symbolize_keys!
6
14
  options[:format] ||= if request.xhr?
7
15
  :json
8
16
  elsif params[:callback]
@@ -10,14 +18,12 @@ module JellyController
10
18
  else
11
19
  :iframe
12
20
  end
13
- render :inline => jelly_callback_erb("on_#{callback_base_name}", options, block)
21
+ render :inline => jelly_callback_erb(options, &block)
14
22
  end
15
23
 
16
- def jelly_callback_erb(callback_name, options, block)
24
+ def jelly_callback_erb(options={}, &block)
17
25
  options[:format] ||= :json
18
- @callback_name = callback_name
19
- @options = options
20
- @block = block
26
+ @jelly_block = block
21
27
  case options[:format].to_sym
22
28
  when :iframe
23
29
  "<textarea>#{jelly_callback_erb_template}</textarea>"
@@ -32,9 +38,7 @@ module JellyController
32
38
  def jelly_callback_erb_template
33
39
  <<-ERB
34
40
  <%= begin
35
- args = @block ? instance_eval(&@block) : []
36
- args = [args] unless args.is_a?(Array)
37
- json = {"method" => @callback_name, "arguments" => args}.reverse_merge(@options).to_json
41
+ json = instance_eval(&@jelly_block).to_json
38
42
  @jsonp_callback ? "\#{@jsonp_callback}(\#{json});" : json
39
43
  end %>
40
44
  ERB
@@ -15,6 +15,54 @@ describe ApplicationController do
15
15
  @controller.respond_to?(:jelly_callback).should be_true
16
16
  end
17
17
 
18
+ context "when given a format" do
19
+ describe "json" do
20
+ it "responds with a json hash, even if the request is not xhr" do
21
+ stub(request).xhr? {false}
22
+
23
+ @controller.send(:jelly_callback, 'foo', {'format' => :json, 'bar' => 'baz'}) do
24
+ "grape"
25
+ end
26
+ callback = JSON.parse(response.body)
27
+ callback["method"].should == "on_foo"
28
+ callback["arguments"].should == ["grape"]
29
+ callback["bar"].should == "baz"
30
+ end
31
+ end
32
+
33
+ describe "jsonp" do
34
+ it "responds with a jsonp callback based on the callback param" do
35
+ @controller.params[:callback] = "Jelly.notifyObservers"
36
+
37
+ @controller.send(:jelly_callback, 'foo', {'format' => :jsonp, 'bar' => 'baz'}) do
38
+ "grape"
39
+ end
40
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
41
+ callback = JSON.parse(json)
42
+ callback["method"].should == "on_foo"
43
+ callback["arguments"].should == ["grape"]
44
+ callback["bar"].should == "baz"
45
+ end
46
+ end
47
+
48
+ describe "iframe" do
49
+ it "responds with a the json in a textarea tag" do
50
+ @controller.send(:jelly_callback, 'foo', {'format' => :iframe, 'bar' => 'baz'}) do
51
+ "grape"
52
+ end
53
+ body = response.body
54
+ body.should =~ /^<textarea>/
55
+ body.should =~ /<\/textarea>$/
56
+ doc = Nokogiri::HTML(body)
57
+
58
+ callback = JSON.parse(doc.at("textarea").inner_html)
59
+ callback["method"].should == "on_foo"
60
+ callback["arguments"].should == ["grape"]
61
+ callback["bar"].should == "baz"
62
+ end
63
+ end
64
+ end
65
+
18
66
  context "when the request is XHR" do
19
67
  before do
20
68
  stub(request).xhr? {true}
@@ -71,81 +119,123 @@ describe ApplicationController do
71
119
  end
72
120
  end
73
121
  end
122
+ end
74
123
 
75
- describe "#jelly_callback_erb" do
76
- before do
77
- stub(request).xhr? {true}
124
+ describe "#raw_jelly_callback" do
125
+ attr_reader :response
126
+ before do
127
+ @response = Struct.new(:body).new
128
+ stub(@controller).render do |params|
129
+ response.body = ERB.new(params[:inline]).result(@controller.send(:binding))
78
130
  end
131
+ end
132
+
133
+ it "have the method included" do
134
+ @controller.respond_to?(:raw_jelly_callback).should be_true
135
+ end
136
+
137
+ context "when given a format" do
138
+ describe "json" do
139
+ it "responds with a json hash, even if the request is not xhr" do
140
+ stub(request).xhr? {false}
79
141
 
80
- context "with options" do
81
- it "should work with a block" do
82
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, lambda{'grape'})
83
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
84
- 'method' => 'foo',
85
- 'arguments' => ['grape'],
86
- 'bar' => 'baz',
87
- 'format' => 'json'
88
- }
142
+ @controller.send(:raw_jelly_callback, :format => :json) do
143
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
144
+ end
145
+ callback = JSON.parse(response.body)
146
+ callback["method"].should == "foo"
147
+ callback["arguments"].should == ["grape"]
148
+ callback["bar"].should == "baz"
89
149
  end
150
+ end
151
+
152
+ describe "jsonp" do
153
+ it "responds with a jsonp callback based on the callback param" do
154
+ @controller.params[:callback] = "Jelly.notifyObservers"
90
155
 
91
- it "should work without a block" do
92
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, nil)
93
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
94
- 'method' => 'foo',
95
- 'arguments' => [],
96
- 'bar' => 'baz',
97
- 'format' => 'json'
98
- }
156
+ @controller.send(:raw_jelly_callback, :format => :jsonp) do
157
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
158
+ end
159
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
160
+ callback = JSON.parse(json)
161
+ callback["method"].should == "foo"
162
+ callback["arguments"].should == ["grape"]
163
+ callback["bar"].should == "baz"
99
164
  end
165
+ end
166
+
167
+ describe "iframe" do
168
+ it "responds with a the json in a textarea tag" do
169
+ @controller.send(:raw_jelly_callback, :format => :iframe) do
170
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
171
+ end
172
+ body = response.body
173
+ body.should =~ /^<textarea>/
174
+ body.should =~ /<\/textarea>$/
175
+ doc = Nokogiri::HTML(body)
100
176
 
101
- it "should work if options are passed with symbol keys" do
102
- erb = @controller.send(:jelly_callback_erb, 'foo', {:bar => 'baz'}, nil)
103
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
104
- 'method' => 'foo',
105
- 'arguments' => [],
106
- 'bar' => 'baz',
107
- 'format' => 'json'
108
- }
177
+ callback = JSON.parse(doc.at("textarea").inner_html)
178
+ callback["method"].should == "foo"
179
+ callback["arguments"].should == ["grape"]
180
+ callback["bar"].should == "baz"
109
181
  end
110
182
  end
183
+ end
184
+
185
+ context "when the request is XHR" do
186
+ before do
187
+ stub(request).xhr? {true}
188
+ end
111
189
 
112
- context "without options" do
113
- it "should work with a block" do
114
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, lambda{'grape'})
115
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
116
- 'method' => 'foo',
117
- 'arguments' => ['grape'],
118
- 'format' => 'json'
119
- }
190
+ it "responds with a json hash" do
191
+ @controller.send(:raw_jelly_callback) do
192
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
120
193
  end
194
+ callback = JSON.parse(response.body)
195
+ callback["method"].should == "foo"
196
+ callback["arguments"].should == ["grape"]
197
+ callback["bar"].should == "baz"
198
+ end
199
+
200
+ end
121
201
 
122
- it "should work with a block of more than one thing" do
123
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, lambda{['grape','tangerine']})
124
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
125
- 'method' => 'foo',
126
- 'arguments' => ['grape','tangerine'],
127
- 'format' => 'json'
128
- }
202
+ context "when the request is not XHR" do
203
+ before do
204
+ stub(request).xhr? {false}
205
+ end
206
+
207
+ context "when there is a callback param" do
208
+ before do
209
+ @controller.params[:callback] = "Jelly.notifyObservers"
129
210
  end
130
211
 
131
- it "should work without a block" do
132
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, nil)
133
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
134
- 'method' => 'foo',
135
- 'arguments' => [],
136
- 'format' => 'json'
137
- }
212
+ it "responds with a call to the given callback method with the json as an argument" do
213
+ @controller.send(:raw_jelly_callback) do
214
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
215
+ end
216
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
217
+ callback = JSON.parse(json)
218
+ callback["method"].should == "foo"
219
+ callback["arguments"].should == ["grape"]
220
+ callback["bar"].should == "baz"
138
221
  end
139
222
  end
140
223
 
141
- it "should escape html in the arguments" do
142
- block = lambda{'<div class="foo"></div>'}
143
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, block)
144
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
145
- 'method' => 'foo',
146
- 'arguments' => ['<div class="foo"></div>'],
147
- 'format' => 'json'
148
- }
224
+ context "when there is not a callback param" do
225
+ it "wraps the json response in a textarea tag to support File Uploads in an iframe target (see: http://malsup.com/jquery/form/#code-samples)" do
226
+ @controller.send(:raw_jelly_callback) do
227
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
228
+ end
229
+ body = response.body
230
+ body.should =~ /^<textarea>/
231
+ body.should =~ /<\/textarea>$/
232
+ doc = Nokogiri::HTML(body)
233
+
234
+ callback = JSON.parse(doc.at("textarea").inner_html)
235
+ callback["method"].should == "foo"
236
+ callback["arguments"].should == ["grape"]
237
+ callback["bar"].should == "baz"
238
+ end
149
239
  end
150
240
  end
151
241
  end
data/spec/spec_helper.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # from the project root directory.
3
3
  ENV["RAILS_ENV"] ||= 'test'
4
4
  ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/rails_root'
5
+ ARGV.push("-b")
5
6
  require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
6
7
  require 'rubygems'
7
8
  gem "test-unit"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honkster-jelly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.7
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pivotal Labs, Inc
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-28 00:00:00 -08:00
12
+ date: 2009-12-29 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency