require 'rails_javascript_helpers' module JqPlotRails module ActionView include RailsJavaScriptHelpers # dom_id:: DOM ID to contain plot (also used for referencing instance) # data:: Array of plot data # opts:: Options hash provided to jqplot # Creates a new plot instance # NOTE: If :raw => true is passed in the opts, the result will be the raw javascript not wrapped within tags def jqplot(dom_id, data, opts={}) output = jqplot_setup output << "window._jqplot_rails['#{_j_key(dom_id)}'] = jQuery.jqplot('#{_j_key(dom_id)}', #{format_type_to_js(data)}, #{format_type_to_js(opts)});".html_safe _j_wrap(opts[:raw], output) end # dom_id:: DOM ID used for the plot # opts:: Ooptions hash for building plot binding # - :function -> RawJS instance with full function defined # - :link_to -> {:url, :remote} # Bind to click event on data and make request def jqplot_data_onclick(dom_id, opts={}) output = jqplot_setup raise 'Only :function or :link_to may be defined, not both.' if opts[:function].present? && opts[:link_to].present? raise 'Must provide :function or :link_to for event.' if opts[:function].blank? && opts[:link_to].blank? function = opts[:link_to].present? ? _j_build_click_url_event(dom_id, opts[:link_to]) : opts[:function] output << jqplot_exists(dom_id) do "jQuery(#{format_type_to_js(format_id(dom_id))}).bind('jqplotDataClick', #{format_type_to_js(function)});".html_safe end _j_wrap(opts[:raw], output) end # dom_id:: DOM ID used for the plot # args:: Extra arguments # Resets the plot to its original state # NOTE: If :raw is passed in the args, the result will be the raw javascript not wrapped within tags def jqplot_reset_plot(dom_id, *args) output = jqplot_setup output << jqplot_exists(dom_id) do "#{jqplot_instance(dom_id)}.replot({clear:true,resetAxes:true});" end _j_wrap(args.include?(:raw), output) end # text:: Button text # dom_id:: DOM ID used for the plot # args:: Extra arguments passed to #button_to_function # Returns a button for resetting the given plot def jqplot_reset_plot_button(text, dom_id, *args) button_to_function(text, jqplot_reset_plot(dom_id, :raw), *args) end # text:: Link text # dom_id:: DOM ID used for the plot # args:: Extra arguments passed to #link_to_function # Returns a link for resetting the given plot def jqplot_reset_plot_link(text, dom_id, *args) link_to_function(text, jqplot_reset_plot(dom_id, :raw), *args) end # dom_id:: DOM ID used for the plot # args:: Extra arguments # Makes the provided plot resizable # NOTE: If :raw is passed in the args, the result will be the raw javascript not wrapped within tags def jqplot_resizable(dom_id, *args) resize_args = args.last if args.last.is_a?(Hash) resize_args ||= {:delay => 20} output = jqplot_setup output << jqplot_exists(dom_id) do "jQuery(#{format_type_to_js(format_id(dom_id))}).resizable(#{format_type_to_js(resize_args)});" + "jQuery(#{format_type_to_js(format_id(dom_id))}).bind('resize', function(event,ui){ #{jqplot_instance(dom_id)}.replot(); });" end _j_wrap(args.include?(:raw), output) end private # Setups up environment for plots (creates storage area) def jqplot_setup output = '' unless(@_jqplot_setup) output << 'if(window._jqplot_rails == undefined){ window._jqplot_rails = {}; }' end output.html_safe end # dom_id:: DOM ID used for the plot # Check for plot instance before continuing def jqplot_exists(dom_id) "if(window._jqplot_rails['#{_j_key(dom_id)}'] != undefined){ #{yield} } else { alert('Failed to locate requested plot instance'); }".html_safe end # dom_id:: DOM ID used for the plot # Returns the plot instance def jqplot_instance(dom_id) "window._jqplot_rails['#{_j_key(dom_id)}']".html_safe end # key:: DOM ID for plot # Helper to remove hash prefix if found def _j_key(key) key.sub('#', '').html_safe end # raw:: Boolean. Raw or wrapped string # string:: Javascript string # Helper to wrap javascript within tag if required def _j_wrap(raw, string) raw ? string.html_safe : javascript_tag{ string.html_safe } end # opts:: Hash # - :url -> Path or symbole # - :use_ticks -> Map index to tick name and pass tick name instead (true defaults to x-axis or :x/:y) # - :remote -> Boolean for ajax call # - :args -> extra arguments for url building def _j_build_click_url_event(dom_id, opts={}) output = 'function(ev, seriesIndex, pointIndex, data){' index = opts[:use_ticks] ? "#{jqplot_instance(dom_id)}.axes.#{opts[:use_ticks] == :y ? 'y' : 'x'}axis.ticks[data[0] - 1]" : "data[0]" if(opts[:url].is_a?(Symbol)) args = ['000'] args += opts[:args] if opts[:args].present? url = RawJS.new("'#{Rails.application.routes.url_helpers.send(opts[:url].to_s.sub('_url', '_path').to_sym, *args)}'.replace('000', #{index})") else url = RawJS.new("'#{opts[:url]}#{opts[:url].include?('?') ? '&' : '?'}jqplot_id='+#{index}") end if(opts[:remote]) output << "jQuery.get(#{format_type_to_js(url)}, null, 'script');" else output << "window.location = #{format_type_to_js(url)};" end output << '}' output.html_safe end end end ActionView::Base.send(:include, JqPlotRails::ActionView)