btakita-jelly 0.6.1 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  module JellyHelper
2
+ include Jelly::Common
2
3
 
3
4
  def application_jelly_files(jelly_files_path_from_javascripts = '', rails_root = RAILS_ROOT)
4
5
  rails_root = File.expand_path(rails_root)
@@ -11,36 +12,45 @@ module JellyHelper
11
12
  end
12
13
 
13
14
  def spread_jelly
15
+ attach_javascript_component("Jelly.Location")
16
+ attach_javascript_component("Jelly.Page", controller.controller_path.camelcase, controller.action_name)
17
+ <<-HTML
18
+ #{window_token_javascript_tag}
19
+ #{attach_javascript_component_javascript_tag(jelly_attached_components)}
20
+ HTML
21
+ end
22
+
23
+ def window_token_javascript_tag
24
+ javascript_tag("window._token = '#{form_authenticity_token}';")
25
+ end
26
+
27
+ def attach_javascript_component_javascript_tag(*components)
28
+ components = [components].flatten
14
29
  javascript_tag <<-JS
15
- window._token = '#{form_authenticity_token}'
16
- Jelly.activatePage('#{controller.controller_path.camelcase}', '#{controller.action_name}');
17
- #{@content_for_javascript}
18
30
  $(document).ready(function() {
19
- #{@content_for_javascript_on_ready}
31
+ Jelly.attach.apply(Jelly, #{components.to_json});
20
32
  });
21
33
  JS
22
34
  end
23
35
 
24
- def clear_jelly_attached()
25
- @jelly_attached_components = []
36
+ def clear_jelly_attached
37
+ jelly_attached_components.clear
26
38
  end
27
39
 
28
40
  def attach_javascript_component(component_name, *args)
29
- @jelly_attached_components ||= []
30
- key = "page.attach(#{component_name}, #{args.to_json});"
31
- unless @jelly_attached_components.include? key
32
- @jelly_attached_components << key
33
- content_for(:javascript, key)
41
+ key = jelly_attach_component_definition_hash(component_name, *args)
42
+ unless jelly_attached_components.include? key
43
+ jelly_attached_components << key
34
44
  end
35
45
  end
36
46
 
37
47
  def attach_javascript_component_on_ready(component_name, *args)
38
- @jelly_attached_components_on_ready ||= []
39
- key = "page.attach(#{component_name}, #{args.to_json});"
40
- unless @jelly_attached_components_on_ready.include? key
41
- @jelly_attached_components_on_ready << key
42
- content_for(:javascript_on_ready, key)
43
- end
48
+ warn "attach_javascript_component_on_ready is deprecated since attach_javascript_component adds components to be attached in a $(document).ready block\n#{puts caller.join("\n\t")}"
49
+ attach_javascript_component(component_name, *args)
50
+ end
51
+
52
+ def jelly_attached_components
53
+ @jelly_attached_components ||= []
44
54
  end
45
55
 
46
56
  end
@@ -3,116 +3,300 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
3
  describe ApplicationController do
4
4
 
5
5
  describe "#jelly_callback" do
6
+ attr_reader :template
6
7
  before do
7
- @controller.stub!(:render)
8
+ stub(@controller).render do |params|
9
+ @template = ActionView::Base.new(@controller.class.view_paths, {}, @controller)
10
+ template.send(:_evaluate_assigns_and_ivars)
11
+ response.body = ERB.new(params[:inline]).result(template.send(:binding))
12
+ end
8
13
  end
9
14
 
10
15
  it "have the method included" do
11
16
  @controller.respond_to?(:jelly_callback).should be_true
12
17
  end
13
18
 
14
- it "should render inline the return of jelly_callback_erb" do
15
- block = lambda{'foo yo'}
16
- mock_erb = "whatever"
17
- @controller.should_receive(:jelly_callback_erb).with("on_foo", {}, block).and_return(mock_erb)
18
- @controller.should_receive(:render).with(:inline => mock_erb)
19
- @controller.send(:jelly_callback, "foo", &block)
20
- end
19
+ describe "Arguments block" do
20
+ describe "self" do
21
+ it "runs with the binding of the ERB template" do
22
+ self_in_block = nil
23
+ @controller.send(:jelly_callback, 'foo', :format => :json) do
24
+ self_in_block = self
25
+ 12345
26
+ end
27
+ self_in_block.should == template
28
+ end
29
+ end
21
30
 
22
- describe "#jelly_callback_erb" do
23
- before do
24
- request.stub!(:xhr?).and_return(true)
31
+ context "when an Array is returned from the block" do
32
+ it "sets the arguments to be an Array around the Hash" do
33
+ @controller.send(:jelly_callback, 'foo', :format => :json) do
34
+ ["foo", "bar"]
35
+ end
36
+ callback = JSON.parse(response.body)
37
+ callback["method"].should == "on_foo"
38
+ callback["arguments"].should == ["foo", "bar"]
39
+ end
25
40
  end
26
41
 
27
- context "with options" do
28
- it "should work with a block" do
29
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, lambda{'grape'})
30
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
31
- 'method' => 'foo',
32
- 'arguments' => ['grape'],
33
- 'bar' => 'baz'
34
- }
42
+ context "when a non-array is returned in the block" do
43
+ context "when the argument is a Hash" do
44
+ it "sets the arguments to be an Array around the Hash" do
45
+ @controller.send(:jelly_callback, 'foo', :format => :json) do
46
+ {"foo" => "bar"}
47
+ end
48
+ callback = JSON.parse(response.body)
49
+ callback["method"].should == "on_foo"
50
+ callback["arguments"].should == [{"foo" => "bar"}]
51
+ end
52
+ end
53
+
54
+ context "when the argument is a String" do
55
+ it "sets the arguments to be an Array around the argument" do
56
+ @controller.send(:jelly_callback, 'foo', :format => :json) do
57
+ "foobar"
58
+ end
59
+ callback = JSON.parse(response.body)
60
+ callback["method"].should == "on_foo"
61
+ callback["arguments"].should == ["foobar"]
62
+ end
35
63
  end
36
64
 
37
- it "should work without a block" do
38
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, nil)
39
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
40
- 'method' => 'foo',
41
- 'arguments' => [],
42
- 'bar' => 'baz'
43
- }
65
+ context "when the argument is a Number" do
66
+ it "sets the arguments to be an Array around the argument" do
67
+ @controller.send(:jelly_callback, 'foo', :format => :json) do
68
+ 12345
69
+ end
70
+ callback = JSON.parse(response.body)
71
+ callback["method"].should == "on_foo"
72
+ callback["arguments"].should == [12345]
73
+ end
44
74
  end
75
+ end
76
+ end
45
77
 
46
- it "should work if options are passed with symbol keys" do
47
- erb = @controller.send(:jelly_callback_erb, 'foo', {:bar => 'baz'}, nil)
48
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
49
- 'method' => 'foo',
50
- 'arguments' => [],
51
- 'bar' => 'baz'
52
- }
78
+ context "when given a format" do
79
+ describe "json" do
80
+ it "responds with a json hash, even if the request is not xhr" do
81
+ stub(request).xhr? {false}
82
+
83
+ @controller.send(:jelly_callback, 'foo', {'format' => :json, 'bar' => 'baz'}) do
84
+ "grape"
85
+ end
86
+ callback = JSON.parse(response.body)
87
+ callback["method"].should == "on_foo"
88
+ callback["arguments"].should == ["grape"]
89
+ callback["bar"].should == "baz"
53
90
  end
54
91
  end
55
92
 
56
- context "without options" do
57
- it "should work with a block" do
58
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, lambda{'grape'})
59
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
60
- 'method' => 'foo',
61
- 'arguments' => ['grape']
62
- }
93
+ describe "jsonp" do
94
+ it "responds with a jsonp callback based on the callback param" do
95
+ @controller.params[:callback] = "Jelly.notifyObservers"
96
+
97
+ @controller.send(:jelly_callback, 'foo', {'format' => :jsonp, 'bar' => 'baz'}) do
98
+ "grape"
99
+ end
100
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
101
+ callback = JSON.parse(json)
102
+ callback["method"].should == "on_foo"
103
+ callback["arguments"].should == ["grape"]
104
+ callback["bar"].should == "baz"
63
105
  end
106
+ end
107
+
108
+ describe "iframe" do
109
+ it "responds with a the json in a textarea tag" do
110
+ @controller.send(:jelly_callback, 'foo', {'format' => :iframe, 'bar' => 'baz'}) do
111
+ "grape"
112
+ end
113
+ body = response.body
114
+ body.should =~ /^<textarea>/
115
+ body.should =~ /<\/textarea>$/
116
+ doc = Nokogiri::HTML(body)
64
117
 
65
- it "should work with a block of more than one thing" do
66
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, lambda{['grape','tangerine']})
67
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
68
- 'method' => 'foo',
69
- 'arguments' => ['grape','tangerine']
70
- }
118
+ callback = JSON.parse(doc.at("textarea").inner_html)
119
+ callback["method"].should == "on_foo"
120
+ callback["arguments"].should == ["grape"]
121
+ callback["bar"].should == "baz"
71
122
  end
123
+ end
124
+ end
72
125
 
73
- it "should work without a block" do
74
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, nil)
75
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
76
- 'method' => 'foo',
77
- 'arguments' => []
78
- }
126
+ context "when the request is XHR" do
127
+ before do
128
+ stub(request).xhr? {true}
129
+ end
130
+
131
+ it "responds with a json hash" do
132
+ @controller.send(:jelly_callback, 'foo', {'bar' => 'baz'}) do
133
+ "grape"
79
134
  end
135
+ callback = JSON.parse(response.body)
136
+ callback["method"].should == "on_foo"
137
+ callback["arguments"].should == ["grape"]
138
+ callback["bar"].should == "baz"
80
139
  end
81
140
 
82
- it "should escape html in the arguments" do
83
- block = lambda{'<div class="foo"></div>'}
84
- erb = @controller.send(:jelly_callback_erb, 'foo', {}, block)
85
- JSON.parse(ERB.new(erb).result(@controller.send(:binding))).should == {
86
- 'method' => 'foo',
87
- 'arguments' => ['<div class="foo"></div>']
88
- }
141
+ end
142
+
143
+ context "when the request is not XHR" do
144
+ before do
145
+ stub(request).xhr? {false}
89
146
  end
90
147
 
91
- context "when the request is not an XHR" do
148
+ context "when there is a callback param" do
92
149
  before do
93
- request.stub!(:xhr?).and_return(false)
150
+ @controller.params[:callback] = "Jelly.notifyObservers"
94
151
  end
95
152
 
96
- it "should wrap json response in a textarea tag to support File Uploads in an iframe target (see: http://malsup.com/jquery/form/#code-samples)" do
97
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, lambda{'grape'})
98
- result = ERB.new(erb).result(@controller.send(:binding))
99
- result.should =~ /^<textarea>/
100
- result.should =~ /<\/textarea>$/
153
+ it "responds with a call to the given callback method with the json as an argument" do
154
+ @controller.send(:jelly_callback, 'foo', {'bar' => 'baz'}) do
155
+ "grape"
156
+ end
157
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
158
+ callback = JSON.parse(json)
159
+ callback["method"].should == "on_foo"
160
+ callback["arguments"].should == ["grape"]
161
+ callback["bar"].should == "baz"
101
162
  end
102
163
  end
103
164
 
104
- context "when the request is an XHR" do
105
- before do
106
- request.stub!(:xhr?).and_return(true)
165
+ context "when there is not a callback param" do
166
+ 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
167
+ @controller.send(:jelly_callback, 'foo', {'bar' => 'baz'}) do
168
+ "grape"
169
+ end
170
+ body = response.body
171
+ body.should =~ /^<textarea>/
172
+ body.should =~ /<\/textarea>$/
173
+ doc = Nokogiri::HTML(body)
174
+
175
+ callback = JSON.parse(doc.at("textarea").inner_html)
176
+ callback["method"].should == "on_foo"
177
+ callback["arguments"].should == ["grape"]
178
+ callback["bar"].should == "baz"
107
179
  end
180
+ end
181
+ end
182
+ end
183
+
184
+ describe "#raw_jelly_callback" do
185
+ attr_reader :response
186
+ before do
187
+ @response = Struct.new(:body).new
188
+ stub(@controller).render do |params|
189
+ response.body = ERB.new(params[:inline]).result(@controller.send(:binding))
190
+ end
191
+ end
108
192
 
109
- it "should not do the textarea nonsense" do
110
- erb = @controller.send(:jelly_callback_erb, 'foo', {'bar' => 'baz'}, lambda{'grape'})
111
- ERB.new(erb).result(@controller.send(:binding)).should_not =~ /textarea/
193
+ it "have the method included" do
194
+ @controller.respond_to?(:raw_jelly_callback).should be_true
195
+ end
196
+
197
+ context "when given a format" do
198
+ describe "json" do
199
+ it "responds with a json hash, even if the request is not xhr" do
200
+ stub(request).xhr? {false}
201
+
202
+ @controller.send(:raw_jelly_callback, :format => :json) do
203
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
204
+ end
205
+ callback = JSON.parse(response.body)
206
+ callback["method"].should == "foo"
207
+ callback["arguments"].should == ["grape"]
208
+ callback["bar"].should == "baz"
209
+ end
210
+ end
211
+
212
+ describe "jsonp" do
213
+ it "responds with a jsonp callback based on the callback param" do
214
+ @controller.params[:callback] = "Jelly.notifyObservers"
215
+
216
+ @controller.send(:raw_jelly_callback, :format => :jsonp) do
217
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
218
+ end
219
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
220
+ callback = JSON.parse(json)
221
+ callback["method"].should == "foo"
222
+ callback["arguments"].should == ["grape"]
223
+ callback["bar"].should == "baz"
224
+ end
225
+ end
226
+
227
+ describe "iframe" do
228
+ it "responds with a the json in a textarea tag" do
229
+ @controller.send(:raw_jelly_callback, :format => :iframe) do
230
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
231
+ end
232
+ body = response.body
233
+ body.should =~ /^<textarea>/
234
+ body.should =~ /<\/textarea>$/
235
+ doc = Nokogiri::HTML(body)
236
+
237
+ callback = JSON.parse(doc.at("textarea").inner_html)
238
+ callback["method"].should == "foo"
239
+ callback["arguments"].should == ["grape"]
240
+ callback["bar"].should == "baz"
112
241
  end
242
+ end
243
+ end
113
244
 
245
+ context "when the request is XHR" do
246
+ before do
247
+ stub(request).xhr? {true}
114
248
  end
115
249
 
250
+ it "responds with a json hash" do
251
+ @controller.send(:raw_jelly_callback) do
252
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
253
+ end
254
+ callback = JSON.parse(response.body)
255
+ callback["method"].should == "foo"
256
+ callback["arguments"].should == ["grape"]
257
+ callback["bar"].should == "baz"
258
+ end
259
+
260
+ end
261
+
262
+ context "when the request is not XHR" do
263
+ before do
264
+ stub(request).xhr? {false}
265
+ end
266
+
267
+ context "when there is a callback param" do
268
+ before do
269
+ @controller.params[:callback] = "Jelly.notifyObservers"
270
+ end
271
+
272
+ it "responds with a call to the given callback method with the json as an argument" do
273
+ @controller.send(:raw_jelly_callback) do
274
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
275
+ end
276
+ json = Regexp.new('Jelly\.notifyObservers\((.*)\);').match(response.body)[1]
277
+ callback = JSON.parse(json)
278
+ callback["method"].should == "foo"
279
+ callback["arguments"].should == ["grape"]
280
+ callback["bar"].should == "baz"
281
+ end
282
+ end
283
+
284
+ context "when there is not a callback param" do
285
+ 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
286
+ @controller.send(:raw_jelly_callback) do
287
+ jelly_callback_hash("foo", "grape").merge('bar' => 'baz')
288
+ end
289
+ body = response.body
290
+ body.should =~ /^<textarea>/
291
+ body.should =~ /<\/textarea>$/
292
+ doc = Nokogiri::HTML(body)
293
+
294
+ callback = JSON.parse(doc.at("textarea").inner_html)
295
+ callback["method"].should == "foo"
296
+ callback["arguments"].should == ["grape"]
297
+ callback["bar"].should == "baz"
298
+ end
299
+ end
116
300
  end
117
301
  end
118
302
  end
@@ -2,14 +2,27 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
2
2
 
3
3
  describe JellyHelper do
4
4
 
5
- describe "#init_specific_javascript" do
6
- it "should create a javascript include tag to initialize the Page object" do
7
- stub_controller = mock(Object, :controller_path => 'my_fun_controller', :action_name => 'super_good_action')
8
- helper.should_receive(:controller).any_number_of_times.and_return(stub_controller)
9
- helper.should_receive(:form_authenticity_token).and_return('areallysecuretoken')
5
+ def jelly_attach_arguments(html)
6
+ JSON.parse(Regexp.new('Jelly\.attach\.apply\(Jelly, (.*)\);').match(html)[1])
7
+ end
8
+
9
+ describe "#spread_jelly" do
10
+ before do
11
+ stub_controller = mock! do |controller|
12
+ controller.controller_path {'my_fun_controller'}
13
+ controller.action_name {'super_good_action'}
14
+ end
15
+ stub(helper).controller {stub_controller}
16
+ mock(helper).form_authenticity_token {'areallysecuretoken'}
17
+ end
18
+
19
+ it "should create a javascript include tag that attaches the Jelly.Location and Jelly.Page components" do
10
20
  output = helper.spread_jelly
11
21
  output.should include('<script type="text/javascript">')
12
- output.should include("Jelly.activatePage('MyFunController', 'super_good_action');")
22
+ doc = Nokogiri::HTML(output)
23
+ argument = jelly_attach_arguments(doc.css("script")[1].inner_html)
24
+ argument.should include({'component' => "Jelly.Location", 'arguments' => []})
25
+ argument.should include({'component' => "Jelly.Page", 'arguments' => ['MyFunController', 'super_good_action']})
13
26
  end
14
27
  end
15
28
 
@@ -34,30 +47,40 @@ describe JellyHelper do
34
47
  end
35
48
 
36
49
  describe "#attach_javascript_component" do
50
+ before do
51
+ def helper.form_authenticity_token
52
+ "12345"
53
+ end
54
+ end
37
55
 
38
56
  after do
39
- #need to clear this since it's saving state between tests
40
- assigns[:content_for_javascript] = ""
41
57
  helper.clear_jelly_attached()
42
58
  end
43
59
 
44
- it "fails to add multiple calls to page.attach for the same component" do
60
+ it "fails to add multiple calls to Jelly.attach for the same component" do
45
61
  helper.attach_javascript_component("MyComponent", 'arg1', 'arg2', 'arg3')
46
62
  helper.attach_javascript_component("MyComponent", 'arg1', 'arg2', 'arg3')
47
63
  helper.attach_javascript_component("MyComponent", 'arg1', 'arg2', 'arg5')
48
- assigns[:content_for_javascript].should == 'page.attach(MyComponent, ["arg1","arg2","arg3"]);page.attach(MyComponent, ["arg1","arg2","arg5"]);'
64
+ assigns[:jelly_attached_components].should == [
65
+ {'component' => "MyComponent", 'arguments' => ['arg1', 'arg2', 'arg3']},
66
+ {'component' => "MyComponent", 'arguments' => ['arg1', 'arg2', 'arg5']},
67
+ ]
49
68
  end
50
69
 
51
- it "adds a call to page.attach in the javascript content" do
70
+ it "adds a call to Jelly.attach in an $(document).ready block" do
52
71
  helper.attach_javascript_component("MyComponent", 'arg1', 'arg2', 'arg3')
53
72
  expected_args = ['arg1','arg2','arg3'].to_json
54
- assigns[:content_for_javascript].should == "page.attach(MyComponent, #{expected_args});"
55
- end
73
+ assigns[:jelly_attached_components].should == [
74
+ {'component' => "MyComponent", 'arguments' => ['arg1', 'arg2', 'arg3']}
75
+ ]
56
76
 
57
- it "adds a call to page.attach in the javascript_on_ready content" do
58
- helper.attach_javascript_component_on_ready("MyComponent", 'arg1', 'arg2', 'arg3')
59
- expected_args = ['arg1','arg2','arg3'].to_json
60
- assigns[:content_for_javascript_on_ready].should == "page.attach(MyComponent, #{expected_args});"
77
+ html = helper.spread_jelly
78
+ doc = Nokogiri::HTML(html)
79
+ document_ready_tag = doc.css("script")[1]
80
+ document_ready_tag.inner_html.should include("$(document).ready(function() {")
81
+ document_ready_part = document_ready_tag.inner_html.split("\n")[3]
82
+ arguments = jelly_attach_arguments(document_ready_part)
83
+ arguments.should include({'component' => "MyComponent", 'arguments' => ['arg1', 'arg2', 'arg3']})
61
84
  end
62
85
 
63
86
  end