4 :jquery_version => "1.4.4",
5 :jqueryui_version => "1.8.6",
10 config_file = File.join("./", "config", "jrails.yml")
11 if File.exist? config_file
12 loaded_config = YAML.load_file(config_file)
13 if loaded_config and loaded_config.key? Rails.env
14 @@config.merge!(loaded_config[Rails.env].symbolize_keys)
16 @@jquery_path = "http://ajax.googleapis.com/ajax/libs/jquery/#{@@config[:jquery_version]}/jquery#{".min" if compressed?}.js"
17 @@jqueryui_path = "http://ajax.googleapis.com/ajax/libs/jqueryui/#{@@config[:jqueryui_version]}/jquery-ui#{".min" if compressed?}.js"
18 @@jqueryui_i18n_path = "http://ajax.googleapis.com/ajax/libs/jqueryui/#{@@config[:jqueryui_version]}/i18n/jquery-ui-i18n#{".min" if compressed?}.js"
21 raise Exception.new "Failed finding '#{Rails.env}' environment in config. check your 'config/jrails.yml' or delete that file "
26 def self.config ; @@config ; end
27 def self.google? ; @@config[:google] ; end
28 def self.compressed? ; @@config[:compressed] ; end
29 def self.jquery_path ; @@jquery_path ; end
30 def self.jqueryui_path ; @@jqueryui_path ; end
31 def self.jqueryui_i18n_path ; @@jqueryui_i18n_path ; end
39 module JavaScriptHelper
41 # This function can be used to render rjs inline
43 # <%= javascript_function do |page|
44 # page.replace_html :list, :partial => 'list', :object => @list
47 def javascript_function(*args, &block)
48 html_options = args.extract_options!
49 function = args[0] || ''
51 html_options.symbolize_keys!
52 function = update_page(&block) if block_given?
53 javascript_tag(function)
57 id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
61 Array(ids).map{|id| jquery_id(id)}.join(',')
66 module PrototypeHelper
68 USE_PROTECTION = const_defined?(:DISABLE_JQUERY_FORGERY_PROTECTION) ? !DISABLE_JQUERY_FORGERY_PROTECTION : true
70 unless const_defined? :JQUERY_VAR
74 unless const_defined? :JQCALLBACKS
75 JQCALLBACKS = Set.new([ :beforeSend, :complete, :error, :success ] + (100..599).to_a)
76 #instance_eval { remove_const :AJAX_OPTIONS }
77 remove_const(:AJAX_OPTIONS) if const_defined?(:AJAX_OPTIONS)
78 AJAX_OPTIONS = Set.new([ :before, :after, :condition, :url,
79 :asynchronous, :method, :insertion, :position,
80 :form, :with, :update, :script ]).merge(JQCALLBACKS)
83 def periodically_call_remote(options = {})
84 frequency = options[:frequency] || 10 # every ten seconds by default
85 code = "setInterval(function() {#{remote_function(options)}}, #{frequency} * 1000)"
89 def remote_function(options)
90 javascript_options = options_for_ajax(options)
93 if options[:update] && options[:update].is_a?(Hash)
95 update << "success:'#{options[:update][:success]}'" if options[:update][:success]
96 update << "failure:'#{options[:update][:failure]}'" if options[:update][:failure]
97 update = '{' + update.join(',') + '}'
98 elsif options[:update]
99 update << "'#{options[:update]}'"
102 function = "#{JQUERY_VAR}.ajax(#{javascript_options})"
104 function = "#{options[:before]}; #{function}" if options[:before]
105 function = "#{function}; #{options[:after]}" if options[:after]
106 function = "if (#{options[:condition]}) { #{function}; }" if options[:condition]
107 function = "if (confirm('#{escape_javascript(options[:confirm])}')) { #{function}; }" if options[:confirm]
111 class JavaScriptGenerator
112 module GeneratorMethods
114 def insert_html(position, id, *options_for_render)
115 insertion = position.to_s.downcase
116 insertion = 'append' if insertion == 'bottom'
117 insertion = 'prepend' if insertion == 'top'
118 call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").#{insertion}", render(*options_for_render)
121 def replace_html(id, *options_for_render)
122 insert_html(:html, id, *options_for_render)
125 def replace(id, *options_for_render)
126 call "#{JQUERY_VAR}(\"#{jquery_id(id)}\").replaceWith", render(*options_for_render)
130 call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").remove"
134 call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").show"
138 call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").hide"
142 call "#{JQUERY_VAR}(\"#{jquery_ids(ids)}\").toggle"
146 id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
150 Array(ids).map{|id| jquery_id(id)}.join(',')
157 def options_for_ajax(options)
158 js_options = build_callbacks(options)
160 url_options = options[:url]
161 url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
162 js_options['url'] = "'#{url_for(url_options)}'"
163 js_options['async'] = false if options[:type] == :synchronous
164 js_options['type'] = options[:method] ? method_option_to_s(options[:method]) : ( options[:form] ? "'post'" : nil )
165 js_options['dataType'] = options[:datatype] ? "'#{options[:datatype]}'" : (options[:update] ? nil : "'script'")
168 js_options['data'] = "#{JQUERY_VAR}.param(#{JQUERY_VAR}(this).serializeArray())"
169 elsif options[:submit]
170 js_options['data'] = "#{JQUERY_VAR}(\"##{options[:submit]} :input\").serialize()"
172 js_options['data'] = options[:with].gsub("Form.serialize(this.form)","#{JQUERY_VAR}.param(#{JQUERY_VAR}(this.form).serializeArray())")
175 js_options['type'] ||= "'post'"
177 if method_option_to_s(options[:method]) == "'put'" || method_option_to_s(options[:method]) == "'delete'"
178 js_options['type'] = "'post'"
179 if js_options['data']
180 js_options['data'] << " + '&"
182 js_options['data'] = "'"
184 js_options['data'] << "_method=#{options[:method]}'"
188 if USE_PROTECTION && respond_to?('protect_against_forgery?') && protect_against_forgery?
189 if js_options['data']
190 js_options['data'] << " + '&"
192 js_options['data'] = "'"
194 js_options['data'] << "#{request_forgery_protection_token}=' + encodeURIComponent('#{escape_javascript form_authenticity_token}')"
196 js_options['data'] = "''" if js_options['type'] == "'post'" && js_options['data'].nil?
197 options_for_javascript(js_options.reject {|key, value| value.nil?})
200 def build_update_for_success(html_id, insertion=nil)
201 insertion = build_insertion(insertion)
202 "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request);"
205 def build_update_for_error(html_id, insertion=nil)
206 insertion = build_insertion(insertion)
207 "#{JQUERY_VAR}('#{jquery_id(html_id)}').#{insertion}(request.responseText);"
210 def build_insertion(insertion)
211 insertion = insertion ? insertion.to_s.downcase : 'html'
212 insertion = 'append' if insertion == 'bottom'
213 insertion = 'prepend' if insertion == 'top'
217 def build_observer(klass, name, options = {})
218 if options[:with] && (options[:with] !~ /[\{=(.]/)
219 options[:with] = "'#{options[:with]}=' + value"
221 options[:with] ||= 'value' unless options[:function]
224 callback = options[:function] || remote_function(options)
225 javascript = "#{JQUERY_VAR}('#{jquery_id(name)}').delayedObserver("
226 javascript << "#{options[:frequency] || 0}, "
227 javascript << "function(element, value) {"
228 javascript << "#{callback}}"
229 #javascript << ", '#{options[:on]}'" if options[:on]
231 javascript_tag(javascript)
234 def build_callbacks(options)
236 options[:beforeSend] = '';
237 [:uninitialized,:loading].each do |key|
238 options[:beforeSend] << (options[key].last == ';' ? options.delete(key) : options.delete(key) << ';') if options[key]
240 options.delete(:beforeSend) if options[:beforeSend].blank?
241 options[:complete] = options.delete(:loaded) if options[:loaded]
242 options[:error] = options.delete(:failure) if options[:failure]
244 if options[:update].is_a?(Hash)
245 options[:update][:error] = options[:update].delete(:failure) if options[:update][:failure]
246 if options[:update][:success]
247 options[:success] = build_update_for_success(options[:update][:success], options[:position]) << (options[:success] ? options[:success] : '')
249 if options[:update][:error]
250 options[:error] = build_update_for_error(options[:update][:error], options[:position]) << (options[:error] ? options[:error] : '')
253 options[:success] = build_update_for_success(options[:update], options[:position]) << (options[:success] ? options[:success] : '')
256 options.each do |callback, code|
257 if JQCALLBACKS.include?(callback)
258 callbacks[callback] = "function(request){#{code}}"
266 class JavaScriptElementProxy < JavaScriptProxy #:nodoc:
268 unless const_defined? :JQUERY_VAR
269 JQUERY_VAR = PrototypeHelper::JQUERY_VAR
272 def initialize(generator, id)
273 id = id.to_s.count('#.*,>+~:[/ ') == 0 ? "##{id}" : id
275 super(generator, "#{JQUERY_VAR}(\"#{id}\")")
278 def replace_html(*options_for_render)
279 call 'html', @generator.send(:render, *options_for_render)
282 def replace(*options_for_render)
283 call 'replaceWith', @generator.send(:render, *options_for_render)
286 def reload(options_for_replace={})
287 replace(options_for_replace.merge({ :partial => @id.to_s.sub(/^#/,'') }))
300 class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\
302 unless const_defined? :JQUERY_VAR
303 JQUERY_VAR = PrototypeHelper::JQUERY_VAR
306 def initialize(generator, pattern)
307 super(generator, "#{JQUERY_VAR}(#{pattern.to_json})")
311 module ScriptaculousHelper
313 unless const_defined? :JQUERY_VAR
314 JQUERY_VAR = PrototypeHelper::JQUERY_VAR
317 unless const_defined? :SCRIPTACULOUS_EFFECTS
318 SCRIPTACULOUS_EFFECTS = {
319 :appear => {:method => 'fadeIn'},
320 :blind_down => {:method => 'blind', :mode => 'show', :options => {:direction => 'vertical'}},
321 :blind_up => {:method => 'blind', :mode => 'hide', :options => {:direction => 'vertical'}},
322 :blind_right => {:method => 'blind', :mode => 'show', :options => {:direction => 'horizontal'}},
323 :blind_left => {:method => 'blind', :mode => 'hide', :options => {:direction => 'horizontal'}},
324 :bounce_in => {:method => 'bounce', :mode => 'show', :options => {:direction => 'up'}},
325 :bounce_out => {:method => 'bounce', :mode => 'hide', :options => {:direction => 'up'}},
326 :drop_in => {:method => 'drop', :mode => 'show', :options => {:direction => 'up'}},
327 :drop_out => {:method => 'drop', :mode => 'hide', :options => {:direction => 'down'}},
328 :fade => {:method => 'fadeOut'},
329 :fold_in => {:method => 'fold', :mode => 'hide'},
330 :fold_out => {:method => 'fold', :mode => 'show'},
331 :grow => {:method => 'scale', :mode => 'show'},
332 :shrink => {:method => 'scale', :mode => 'hide'},
333 :slide_down => {:method => 'slide', :mode => 'show', :options => {:direction => 'up'}},
334 :slide_up => {:method => 'slide', :mode => 'hide', :options => {:direction => 'up'}},
335 :slide_right => {:method => 'slide', :mode => 'show', :options => {:direction => 'left'}},
336 :slide_left => {:method => 'slide', :mode => 'hide', :options => {:direction => 'left'}},
337 :squish => {:method => 'scale', :mode => 'hide', :options => {:origin => "['top','left']"}},
338 :switch_on => {:method => 'clip', :mode => 'show', :options => {:direction => 'vertical'}},
339 :switch_off => {:method => 'clip', :mode => 'hide', :options => {:direction => 'vertical'}},
340 :toggle_appear => {:method => 'fadeToggle'},
341 :toggle_slide => {:method => 'slide', :mode => 'toggle', :options => {:direction => 'up'}},
342 :toggle_blind => {:method => 'blind', :mode => 'toggle', :options => {:direction => 'vertical'}},
346 def visual_effect(name, element_id = false, js_options = {})
347 element = element_id ? element_id : "this"
349 if SCRIPTACULOUS_EFFECTS.has_key? name.to_sym
350 effect = SCRIPTACULOUS_EFFECTS[name.to_sym]
351 name = effect[:method]
353 js_options = js_options.merge(effect[:options]) if effect[:options]
356 [:color, :direction, :startcolor, :endcolor].each do |option|
357 js_options[option] = "'#{js_options[option]}'" if js_options[option]
360 if js_options.has_key? :duration
361 speed = js_options.delete :duration
362 speed = (speed * 1000).to_i unless speed.nil?
364 speed = js_options.delete :speed
367 if ['fadeIn','fadeOut','fadeToggle'].include?(name)
368 # 090905 - Jake - changed ' to \" so it passes assert_select_rjs with an id
369 javascript = "#{JQUERY_VAR}(\"#{jquery_id(element_id)}\").#{name}("
370 javascript << "#{speed}" unless speed.nil?
373 # 090905 - Jake - changed ' to \" so it passes "assert_select_rjs :effect, ID"
374 javascript = "#{JQUERY_VAR}(\"#{jquery_id(element_id)}\").#{mode || 'effect'}('#{name}'"
375 javascript << ",#{options_for_javascript(js_options)}" unless speed.nil? && js_options.empty?
376 javascript << ",#{speed}" unless speed.nil?
382 def sortable_element_js(element_id, options = {}) #:nodoc:
383 #convert similar attributes
384 options[:handle] = ".#{options[:handle]}" if options[:handle]
385 if options[:tag] || options[:only]
386 options[:items] = "> "
387 options[:items] << options.delete(:tag) if options[:tag]
388 options[:items] << ".#{options.delete(:only)}" if options[:only]
390 options[:connectWith] = options.delete(:containment).map {|x| "##{x}"} if options[:containment]
391 options[:containment] = options.delete(:container) if options[:container]
392 options[:dropOnEmpty] = false unless options[:dropOnEmpty]
393 options[:helper] = "'clone'" if options[:ghosting] == true
394 options[:axis] = case options.delete(:constraint)
395 when "vertical", :vertical
397 when "horizontal", :horizontal
404 options.delete(:axis) if options[:axis].nil?
405 options.delete(:overlap)
406 options.delete(:ghosting)
408 if options[:onUpdate] || options[:url]
410 options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]', expression:#{options[:format]}})"
411 options.delete(:format)
413 options[:with] ||= "#{JQUERY_VAR}(this).sortable('serialize',{key:'#{element_id}[]'})"
416 options[:onUpdate] ||= "function(){" + remote_function(options) + "}"
419 options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
420 options[:update] = options.delete(:onUpdate) if options[:onUpdate]
422 [:axis, :cancel, :containment, :cursor, :handle, :tolerance, :items, :placeholder].each do |option|
423 options[option] = "'#{options[option]}'" if options[option]
426 options[:connectWith] = array_or_string_for_javascript(options[:connectWith]) if options[:connectWith]
428 %(#{JQUERY_VAR}('#{jquery_id(element_id)}').sortable(#{options_for_javascript(options)});)
431 def draggable_element_js(element_id, options = {})
432 %(#{JQUERY_VAR}("#{jquery_id(element_id)}").draggable(#{options_for_javascript(options)});)
435 def drop_receiving_element_js(element_id, options = {})
436 #convert similar options
437 options[:hoverClass] = options.delete(:hoverclass) if options[:hoverclass]
438 options[:drop] = options.delete(:onDrop) if options[:onDrop]
440 if options[:drop] || options[:url]
441 options[:with] ||= "'id=' + encodeURIComponent(#{JQUERY_VAR}(ui.draggable).attr('id'))"
442 options[:drop] ||= "function(ev, ui){" + remote_function(options) + "}"
445 options.delete_if { |key, value| PrototypeHelper::AJAX_OPTIONS.include?(key) }
447 options[:accept] = array_or_string_for_javascript(options[:accept]) if options[:accept]
448 [:activeClass, :hoverClass, :tolerance].each do |option|
449 options[option] = "'#{options[option]}'" if options[option]
452 %(#{JQUERY_VAR}('#{jquery_id(element_id)}').droppable(#{options_for_javascript(options)});)