require 'mjs/java_script_context' module Mjs module Helper def page @page ||= Mjs::JavaScriptContext.new end def remote_function(opts) build_href(opts) if opts[:submit] "$.ajax(%s);" % options_for_ajax(opts) else "$.getScript('#{opts[:href]}')" end end # experimental: not tested yet def button_to(name, url='', opts={}) ajax = remote_function(opts) opts[:type] = 'button' opts[:value] = name opts[:remote] ||= true if opts[:submit] if opts.delete(:remote) ajax = remote_function(opts) opts[:onclick] = "#{opts.delete(:onclick)}; #{ajax}; return false;" end %{} end # override! :link_to # for Ajax def link_to(name, url='', opts={}) opts[:href] ||= url opts[:remote] ||= true if opts[:submit] return super unless opts.delete(:remote) ajax = remote_function(opts) opts[:onclick] = "#{opts.delete(:onclick)}; #{ajax}; return false;" opts[:href] = '#' %{#{name}} end ###################################################################### ### derived from actionpack JS_ESCAPE_MAP = { '\\' => '\\\\', ' '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'" } # Escape carrier returns and single and double quotes for JavaScript segments. def escape_javascript(javascript) if javascript javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] } else '' end end private def build_href(opts) if opts[:href].is_a?(DataMapper::Resource) record = opts[:href] if record.new_record? opts[:href] = resource(record.class.name.downcase.pluralize.intern, :new) else opts[:href] = resource(record) end end opts end AJAX_FUNCTIONS = { :before => :beforeSend, :before_send => :beforeSend, :beforeSend => :beforeSend, :complete => :complete, :success => :success, :error => :error, :dataFilter => :dataFilter, :data_filter => :dataFilter, :xhr => :xhr, } def options_for_ajax(options) js_options = build_callbacks!(options) submit = options.delete(:submit) target = case submit when Symbol then "$('##{submit} input')" when String then "$('#{submit}')" when NilClass # GET requst else raise ArgumentError, "link_to :submit expects Symbol or String, but got #{submit.class.name}" end build_href(options) js_options[:type] = "'POST'" js_options[:url] = "'#{options[:href]}'" js_options[:data] = "#{target}.serialize()" js_options[:dataType] = "'script'" options_for_javascript(js_options) end def options_for_javascript(options) if options.empty? '{}' else "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}" end end def jquery_selector(key) case key when Symbol then "$('##{key}')" when String then "$('#{key}')" else raise "invalid jquery selector: [#{key.class}] #{key}" end end # this method affects "options" def build_callbacks!(options) callbacks = {} # special callback spinner = options.delete(:spinner) if spinner options[:before] = [options[:before], "%s.show()" % jquery_selector(spinner)].compact * ';' options[:complete] = [options[:complete], "%s.hide()" % jquery_selector(spinner)].compact * ';' end options.each do |callback, code| if (name = AJAX_FUNCTIONS[callback]) callbacks[name.to_s] = "function(request){#{code}}" options.delete(callback) end end callbacks end end end