aaronchi-jrails 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/jrails.rb ADDED
@@ -0,0 +1,421 @@
1
+ module ActionView
2
+ module Helpers
3
+
4
+ module JavaScriptHelper
5
+
6
+ # This function can be used to render rjs inline
7
+ #
8
+ # <%= javascript_function do |page|
9
+ # page.replace_html :list, :partial => 'list', :object => @list
10
+ # end %>
11
+ #
12
+ def javascript_function(*args, &block)
13
+ html_options = args.extract_options!
14
+ function = args[0] || ''
15
+
16
+ html_options.symbolize_keys!
17
+ function = update_page(&block) if block_given?
18
+ javascript_tag(function)
19
+ end
20
+
21
+ def jquery_id(id)
22
+ id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
23
+ end
24
+
25
+ def jquery_ids(ids)
26
+ Array(ids).map{|id| jquery_id(id)}.join(',')
27
+ end
28
+
29
+ end
30
+
31
+ module PrototypeHelper
32
+
33
+ USE_PROTECTION = const_defined?(:DISABLE_JQUERY_FORGERY_PROTECTION) ? !DISABLE_JQUERY_FORGERY_PROTECTION : true
34
+
35
+ unless const_defined? :JQUERY_VAR
36
+ JQUERY_VAR = '$'
37
+ end
38
+
39
+ unless const_defined? :JQCALLBACKS
40
+ JQCALLBACKS = Set.new([ :beforeSend, :complete, :error, :success ] + (100..599).to_a)
41
+ #instance_eval { remove_const :AJAX_OPTIONS }
42
+ remove_const(:AJAX_OPTIONS) if const_defined?(:AJAX_OPTIONS)
43
+ AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
44
+ :asynchronous, :method, :insertion, :position,
45
+ :form, :with, :update, :script ]).merge(JQCALLBACKS)
46
+ end
47
+
48
+ def periodically_call_remote(options = {})
49
+ frequency = options[:frequency] || 10 # every ten seconds by default
50
+ code = "setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)"
51
+ javascript_tag(code)
52
+ end
53
+
54
+ def remote_function(options)
55
+ javascript_options = options_for_ajax(options)
56
+
57
+ update = ''
58
+ if options[:update] && options[:update].is_a?(Hash)
59
+ update = []
60
+ update << "success:'#{options[:update][:success]}'" if options[:update][:success]
61
+ update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
62
+ update = '{' + update.join(',') + '}'
63
+ elsif options[:update]
64
+ update << "'#{options[:update]}'"
65
+ end
66
+
67
+ function = "#{JQUERY_VAR}.ajax(#{javascript_options})"
68
+
69
+ function = "#{options[:before]}; #{function}" if options[:before]
70
+ function = "#{function}; #{options[:after]}" if options[:after]
71
+ function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
72
+ function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
73
+ return function
74
+ end
75
+
76
+ class JavaScriptGenerator
77
+ module GeneratorMethods
78
+
79
+ def insert_html(position, id, *options_for_render)
80
+ insertion = position.to_s.downcase
81
+ insertion = 'append' if insertion == 'bottom'
82
+ insertion = 'prepend' if insertion == 'top'
83
+ call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").#{insertion}", render(*options_for_render)
84
+ end
85
+
86
+ def replace_html(id, *options_for_render)
87
+ insert_html(:html, id, *options_for_render)
88
+ end
89
+
90
+ def replace(id, *options_for_render)
91
+ call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").replaceWith", render(*options_for_render)
92
+ end
93
+
94
+ def remove(*ids)
95
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").remove"
96
+ end
97
+
98
+ def show(*ids)
99
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").show"
100
+ end
101
+
102
+ def hide(*ids)
103
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").hide"
104
+ end
105
+
106
+ def toggle(*ids)
107
+ call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").toggle"
108
+ end
109
+
110
+ def jquery_id(id)
111
+ id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
112
+ end
113
+
114
+ def jquery_ids(ids)
115
+ Array(ids).map{|id| jquery_id(id)}.join(',')
116
+ end
117
+
118
+ end
119
+ end
120
+
121
+ protected
122
+ def options_for_ajax(options)
123
+ js_options = build_callbacks(options)
124
+
125
+ url_options = options[:url]
126
+ url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
127
+ js_options['url'] = "'#{url_for(url_options)}'"
128
+ js_options['async'] = false if options[:type] == :synchronous
129
+ js_options['type'] = options[:method] ? method_option_to_s(options[:method]) : ( options[:form] ? "'post'" : nil )
130
+ js_options['dataType'] = options[:datatype] ? "'#{options[:datatype]}'" : (options[:update] ? nil : "'script'")
131
+
132
+ if options[:form]
133
+ js_options['data'] = "#{JQUERY_VAR}.param(#{JQUERY_VAR}(this).serializeArray())"
134
+ elsif options[:submit]
135
+ js_options['data'] = "#{JQUERY_VAR}(\"##{options[:submit]} :input\").serialize()"
136
+ elsif options[:with]
137
+ js_options['data'] = options[:with].gsub("Form.serialize(this.form)","#{JQUERY_VAR}.param(#{JQUERY_VAR}(this.form).serializeArray())")
138
+ end
139
+
140
+ js_options['type'] ||= "'post'"
141
+ if options[:method]
142
+ if method_option_to_s(options[:method]) == "'put'" || method_option_to_s(options[:method]) == "'delete'"
143
+ js_options['type'] = "'post'"
144
+ if js_options['data']
145
+ js_options['data'] << " + '&"
146
+ else
147
+ js_options['data'] = "'"
148
+ end
149
+ js_options['data'] << "_method=#{options[:method]}'"
150
+ end
151
+ end
152
+
153
+ if USE_PROTECTION && respond_to?('protect_against_forgery?') && protect_against_forgery?
154
+ if js_options['data']
155
+ js_options['data'] << " + '&"
156
+ else
157
+ js_options['data'] = "'"
158
+ end
159
+ js_options['data'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
160
+ end
161
+ js_options['data'] = "''" if js_options['type'] == "'post'" && js_options['data'].nil?
162
+ options_for_javascript(js_options.reject {|key, value| value.nil?})
163
+ end
164
+
165
+ def build_update_for_success(html_id, insertion=nil)
166
+ insertion = build_insertion(insertion)
167
+ "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request);"
168
+ end
169
+
170
+ def build_update_for_error(html_id, insertion=nil)
171
+ insertion = build_insertion(insertion)
172
+ "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request.responseText);"
173
+ end
174
+
175
+ def build_insertion(insertion)
176
+ insertion = insertion ? insertion.to_s.downcase : 'html'
177
+ insertion = 'append' if insertion == 'bottom'
178
+ insertion = 'prepend' if insertion == 'top'
179
+ insertion
180
+ end
181
+
182
+ def build_observer(klass, name, options = {})
183
+ if options[:with] && (options[:with] !~ /[\{=(.]/)
184
+ options[:with] = "'#{options[:with]}=' + value"
185
+ else
186
+ options[:with] ||= 'value' unless options[:function]
187
+ end
188
+
189
+ callback = options[:function] || remote_function(options)
190
+ javascript = "#{JQUERY_VAR}('#{jquery_id(name)}').delayedObserver("
191
+ javascript << "#{options[:frequency] || 0}, "
192
+ javascript << "function(element, value) {"
193
+ javascript << "#{callback}}"
194
+ #javascript << ", '#{options[:on]}'" if options[:on]
195
+ javascript << ")"
196
+ javascript_tag(javascript)
197
+ end
198
+
199
+ def build_callbacks(options)
200
+ callbacks = {}
201
+ options[:beforeSend] = '';
202
+ [:uninitialized,:loading].each do |key|
203
+ options[:beforeSend] << (options[key].last == ';' ? options.delete(key) : options.delete(key) << ';') if options[key]
204
+ end
205
+ options.delete(:beforeSend) if options[:beforeSend].blank?
206
+ options[:complete] = options.delete(:loaded) if options[:loaded]
207
+ options[:error] = options.delete(:failure) if options[:failure]
208
+ if options[:update]
209
+ if options[:update].is_a?(Hash)
210
+ options[:update][:error] = options[:update].delete(:failure) if options[:update][:failure]
211
+ if options[:update][:success]
212
+ options[:success] = build_update_for_success(options[:update][:success], options[:position]) << (options[:success] ? options[:success] : '')
213
+ end
214
+ if options[:update][:error]
215
+ options[:error] = build_update_for_error(options[:update][:error], options[:position]) << (options[:error] ? options[:error] : '')
216
+ end
217
+ else
218
+ options[:success] = build_update_for_success(options[:update], options[:position]) << (options[:success] ? options[:success] : '')
219
+ end
220
+ end
221
+ options.each do |callback, code|
222
+ if JQCALLBACKS.include?(callback)
223
+ callbacks[callback] = "function(request){#{code}}"
224
+ end
225
+ end
226
+ callbacks
227
+ end
228
+
229
+ end
230
+
231
+ class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
232
+
233
+ unless const_defined? :JQUERY_VAR
234
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
235
+ end
236
+
237
+ def initialize(generator, id)
238
+ id = id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
239
+ @id = id
240
+ super(generator, "#{JQUERY_VAR}(\"#{id}\")")
241
+ end
242
+
243
+ def replace_html(*options_for_render)
244
+ call 'html', @generator.send(:render, *options_for_render)
245
+ end
246
+
247
+ def replace(*options_for_render)
248
+ call 'replaceWith', @generator.send(:render, *options_for_render)
249
+ end
250
+
251
+ def reload(options_for_replace={})
252
+ replace(options_for_replace.merge({ :partial => @id.to_s.sub(/^#/,'') }))
253
+ end
254
+
255
+ def value()
256
+ call 'val()'
257
+ end
258
+
259
+ def value=(value)
260
+ call 'val', value
261
+ end
262
+
263
+ end
264
+
265
+ class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
266
+
267
+ unless const_defined? :JQUERY_VAR
268
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
269
+ end
270
+
271
+ def initialize(generator, pattern)
272
+ super(generator, "#{JQUERY_VAR}(#{pattern.to_json})")
273
+ end
274
+ end
275
+
276
+ module ScriptaculousHelper
277
+
278
+ unless const_defined? :JQUERY_VAR
279
+ JQUERY_VAR = PrototypeHelper::JQUERY_VAR
280
+ end
281
+
282
+ unless const_defined? :SCRIPTACULOUS_EFFECTS
283
+ SCRIPTACULOUS_EFFECTS = {
284
+ :appear => {:method => 'fadeIn'},
285
+ :blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},
286
+ :blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},
287
+ :blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},
288
+ :blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},
289
+ :bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},
290
+ :bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},
291
+ :drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},
292
+ :drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},
293
+ :fade => {:method => 'fadeOut'},
294
+ :fold_in => {:method => 'fold', :mode => 'hide'},
295
+ :fold_out => {:method => 'fold', :mode => 'show'},
296
+ :grow => {:method => 'scale', :mode => 'show'},
297
+ :shrink => {:method => 'scale', :mode => 'hide'},
298
+ :slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},
299
+ :slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},
300
+ :slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},
301
+ :slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},
302
+ :squish => {:method => 'scale', :mode => 'hide', :options => {:origin => "['top','left']"}},
303
+ :switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},
304
+ :switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},
305
+ :toggle_appear => {:method => 'fadeToggle'},
306
+ :toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},
307
+ :toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},
308
+ }
309
+ end
310
+
311
+ def visual_effect(name, element_id = false, js_options = {})
312
+ element = element_id ? element_id : "this"
313
+
314
+ if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym
315
+ effect = SCRIPTACULOUS_EFFECTS[name.to_sym]
316
+ name = effect[:method]
317
+ mode = effect[:mode]
318
+ js_options = js_options.merge(effect[:options]) if effect[:options]
319
+ end
320
+
321
+ [:color, :direction, :startcolor, :endcolor].each do |option|
322
+ js_options[option] = "'#{js_options[option]}'" if js_options[option]
323
+ end
324
+
325
+ if js_options.has_key? :duration
326
+ speed = js_options.delete :duration
327
+ speed = (speed * 1000).to_i unless speed.nil?
328
+ else
329
+ speed = js_options.delete :speed
330
+ end
331
+
332
+ if ['fadeIn','fadeOut','fadeToggle'].include?(name)
333
+ javascript = "#{JQUERY_VAR}('#{jquery_id(element_id)}').#{name}("
334
+ javascript << "#{speed}" unless speed.nil?
335
+ javascript << ");"
336
+ else
337
+ javascript = "#{JQUERY_VAR}('#{jquery_id(element_id)}').#{mode || 'effect'}('#{name}'"
338
+ javascript << ",#{options_for_javascript(js_options)}" unless speed.nil? && js_options.empty?
339
+ javascript << ",#{speed}" unless speed.nil?
340
+ javascript << ");"
341
+ end
342
+
343
+ end
344
+
345
+ def sortable_element_js(element_id, options = {}) #:nodoc:
346
+ #convert similar attributes
347
+ options[:handle] = ".#{options[:handle]}" if options[:handle]
348
+ if options[:tag] || options[:only]
349
+ options[:items] = "> "
350
+ options[:items] << options.delete(:tag) if options[:tag]
351
+ options[:items] << ".#{options.delete(:only)}" if options[:only]
352
+ end
353
+ options[:connectWith] = options.delete(:containment).map {|x| "##{x}"} if options[:containment]
354
+ options[:containment] = options.delete(:container) if options[:container]
355
+ options[:dropOnEmpty] = false unless options[:dropOnEmpty]
356
+ options[:helper] = "'clone'" if options[:ghosting] == true
357
+ options[:axis] = case options.delete(:constraint)
358
+ when "vertical", :vertical
359
+ "y"
360
+ when "horizontal", :horizontal
361
+ "x"
362
+ when false
363
+ nil
364
+ when nil
365
+ "y"
366
+ end
367
+ options.delete(:axis) if options[:axis].nil?
368
+ options.delete(:overlap)
369
+ options.delete(:ghosting)
370
+
371
+ if options[:onUpdate] || options[:url]
372
+ if options[:format]
373
+ options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]', expression:#{options[:format]}})"
374
+ options.delete(:format)
375
+ else
376
+ options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]'})"
377
+ end
378
+
379
+ options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
380
+ end
381
+
382
+ options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
383
+ options[:update] = options.delete(:onUpdate) if options[:onUpdate]
384
+
385
+ [:axis, :cancel, :containment, :cursor, :handle, :tolerance, :items, :placeholder].each do |option|
386
+ options[option] = "'#{options[option]}'" if options[option]
387
+ end
388
+
389
+ options[:connectWith] = array_or_string_for_javascript(options[:connectWith]) if options[:connectWith]
390
+
391
+ %(#{JQUERY_VAR}('#{jquery_id(element_id)}').sortable(#{options_for_javascript(options)});)
392
+ end
393
+
394
+ def draggable_element_js(element_id, options = {})
395
+ %(#{JQUERY_VAR}("#{jquery_id(element_id)}").draggable(#{options_for_javascript(options)});)
396
+ end
397
+
398
+ def drop_receiving_element_js(element_id, options = {})
399
+ #convert similar options
400
+ options[:hoverClass] = options.delete(:hoverclass) if options[:hoverclass]
401
+ options[:drop] = options.delete(:onDrop) if options[:onDrop]
402
+
403
+ if options[:drop] || options[:url]
404
+ options[:with] ||= "'id=' + encodeURIComponent(#{JQUERY_VAR}(ui.draggable).attr('id'))"
405
+ options[:drop] ||= "function(ev, ui){" + remote_function(options) + "}"
406
+ end
407
+
408
+ options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
409
+
410
+ options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
411
+ [:activeClass, :hoverClass, :tolerance].each do |option|
412
+ options[option] = "'#{options[option]}'" if options[option]
413
+ end
414
+
415
+ %(#{JQUERY_VAR}('#{jquery_id(element_id)}').droppable(#{options_for_javascript(options)});)
416
+ end
417
+
418
+ end
419
+
420
+ end
421
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,19 @@
1
+ # ====
2
+ # The following options can be changed by creating an initializer in config/initializers/jrails.rb
3
+ # ====
4
+ # ActionView::Helpers::PrototypeHelper::JQUERY_VAR
5
+ # jRails uses jQuery.noConflict() by default
6
+ # to use the regular jQuery syntax, use:
7
+ # ActionView::Helpers::PrototypeHelper::JQUERY_VAR = '$'
8
+ ActionView::Helpers::PrototypeHelper::JQUERY_VAR = 'jQuery'
9
+
10
+ # ActionView::Helpers::PrototypeHelper:: DISABLE_JQUERY_FORGERY_PROTECTION
11
+ # Set this to disable forgery protection in ajax calls
12
+ # This is handy if you want to use caching with ajax by injecting the forgery token via another means
13
+ # for an example, see http://henrik.nyh.se/2008/05/rails-authenticity-token-with-jquery
14
+ # ActionView::Helpers::PrototypeHelper::DISABLE_JQUERY_FORGERY_PROTECTION = true
15
+ # ====
16
+
17
+ ActionView::Helpers::AssetTagHelper::JAVASCRIPT_DEFAULT_SOURCES = ['jquery','jquery-ui','jrails']
18
+ ActionView::Helpers::AssetTagHelper::reset_javascript_include_default
19
+ require 'jrails'
data/tasks/jrails.rake ADDED
@@ -0,0 +1,28 @@
1
+ namespace :jrails do
2
+ namespace :update do
3
+ desc "Copies the jQuery and jRails javascripts to public/javascripts"
4
+ task :javascripts do
5
+ puts "Copying files..."
6
+ project_dir = RAILS_ROOT + '/public/javascripts/'
7
+ scripts = Dir[File.join(File.dirname(__FILE__), '..', '/javascripts/', '*.js')]
8
+ FileUtils.cp(scripts, project_dir)
9
+ puts "files copied successfully."
10
+ end
11
+ end
12
+
13
+ namespace :install do
14
+ desc "Installs the jQuery and jRails javascripts to public/javascripts"
15
+ task :javascripts do
16
+ Rake::Task['jrails:update:javascripts'].invoke
17
+ end
18
+ end
19
+
20
+ desc 'Remove the prototype / script.aculo.us javascript files'
21
+ task :scrub do
22
+ files = %W[controls.js dragdrop.js effects.js prototype.js]
23
+ project_dir = File.join(RAILS_ROOT, 'public', 'javascripts')
24
+ files.each do |fname|
25
+ FileUtils.rm File.join(project_dir, fname)
26
+ end
27
+ end
28
+ end