module SwfFu DEFAULTS = { :width => "100%", :height => "100%", :flash_version => 7, :mode => :dynamic, :auto_install => "expressInstall", :alt => <<-"EOS".squeeze(" ").strip.freeze EOS }.freeze class Generator # :nodoc: VALID_MODES = [:static, :dynamic] def initialize(source, options, view) @view = view @source = view.swf_path(source) options = ActionView::Base.swf_default_options.merge(options) options.each do |key, value| options[key] = value.call(source) if value.respond_to?(:call) end [:html_options, :parameters, :flashvars].each do |k| options[k] = convert_to_hash(options[k]).reverse_merge convert_to_hash(ActionView::Base.swf_default_options[k]) end options.reverse_merge!(DEFAULTS) options[:id] ||= source.gsub(/^.*\//, '').gsub(/\.swf$/,'') options[:id] = force_to_valid_id(options[:id]) options[:div_id] ||= options[:id]+"_div" options[:div_id] = force_to_valid_id(options[:div_id]) options[:width], options[:height] = options[:size].scan(/^(\d*%?)x(\d*%?)$/).first if options[:size] options[:auto_install] &&= @view.swf_path(options[:auto_install]) options[:flashvars][:id] ||= options[:id] @mode = options.delete(:mode) @options = options unless VALID_MODES.include? @mode raise ArgumentError, "options[:mode] should be either #{VALID_MODES.join(' or ')}" end end def force_to_valid_id(id) id = id.gsub /[^A-Za-z0-9\-_]/, "_" # HTML id can only contain these characters id = "swf_" + id unless id =~ /^[A-Z]/i # HTML id must start with alpha id end def generate(&block) @options[:alt] = @view.capture(&block) if block_given? send(@mode) end private def convert_to_hash(s) case s when Hash s when nil {} when String s.split("&").inject({}) do |h, kvp| key, value = kvp.split("=") h[key.to_sym] = CGI::unescape(value) h end else raise ArgumentError, "#{s} should be a Hash, a String or nil" end end def convert_to_string(h) h.map do |key_value| key_value.map{|val| CGI::escape(val.to_s)}.join("=") end.join("&") end def static param_list = @options[:parameters].map{|k,v| %() }.join("\n") param_list += %(\n) unless @options[:flashvars].empty? html_options = @options[:html_options].map{|k,v| %(#{k}="#{v}")}.join(" ") r = @view.javascript_tag( %(swfobject.registerObject("#{@options[:id]}_container", "#{@options[:flash_version]}", #{convert_to_escaped_arguments(@options[:auto_install])});) ) r << <<-"EOS".strip.html_safe
EOS r << @view.javascript_tag(extend_js) if @options[:javascript_class] r << library_check r end def dynamic @options[:html_options] = @options[:html_options].merge(:id => @options[:id]) @options[:parameters] = @options[:parameters].dup # don't modify the original parameters args = convert_to_escaped_arguments(@source, *(@options.values_at(:div_id,:width,:height,:flash_version).map(&:to_s) + @options.values_at(:auto_install,:flashvars,:parameters,:html_options)) ) preambule = @options[:switch_off_auto_hide_show] ? "swfobject.switchOffAutoHideShow();" : "" r = @view.javascript_tag(preambule + "swfobject.embedSWF(#{args})") r << @view.content_tag("div", @options[:alt].html_safe, :id => @options[:div_id]) r << @view.javascript_tag("swfobject.addDomLoadEvent(function(){#{extend_js}})") if @options[:javascript_class] r << library_check r end def convert_to_escaped_arguments(*values) # Note: Rails used to escape <>& but it's now a setting values.map(&:to_json).join(",").gsub('>', '\u003E').gsub('<', '\u003C').gsub('&', '\u0026') end def extend_js args = @options[:initialize] args = [args] unless args.is_a?(Array) "SwfFu.setup($('##{@options[:id]}')[0], #{@options[:javascript_class]}, [#{convert_to_escaped_arguments(*args)}])" end def library_check return "" unless 'development' == ENV['RAILS_ENV'] @view.javascript_tag(<<-"EOS") if (typeof swfobject == 'undefined') { document.getElementById('#{@options[:div_id]}').innerHTML = 'Warning: SWFObject.js was not loaded properly. Make sure you require "swfobject" in your main javascript file.'; } EOS end end #class Generator end