require 'rubygems' require 'epic' module YMDP # Contains all the functions which are available from inside a view file, whether that view # is HTML, JavaScript or CSS. # module ApplicationView extend self # Returns an array of the country codes of all languages supported by the application, # which is determined by the language-specific folders in "app/assets/yrb". # # ==== Examples # # supported_languages # # => ["en-US", "de-DE", "es-ES", "es-MX"] # def supported_languages dirs = Dir["#{BASE_PATH}/app/assets/yrb/*"].map do |path| filename = path.split("/").last filename end dirs.unshift(dirs.delete("en-US")) raise "Default YRB key en-US not found" unless dirs.include?("en-US") dirs end # Returns an array of country codes of English-speaking countries supported # by the application, based on the language-specific folders located in "app/assets/yrb". # # ==== Examples # # english_languages # # => ["en-US", "en-AU", "en-SG", "en-MY"] # def english_languages supported_languages.select do |lang| lang =~ /^en/ end end # Includes a JavaScript file in a view. If the filename is a full path, the # JavaScript file will be linked as an external asset. If not, the file will # linked as a local asset located in the YMDP application's assets directory. # # === Local JavaScript Assets # # javascript_include("application.js") # # will produce: # # # # === External JavaScript Assets # # javascript_include("http://www.myserver.com/javascripts/application.js") # # will produce: # # # def javascript_include(filename) unless filename =~ /^http/ filename = "#{@assets_directory}/javascripts/#{filename}" end "" end # Renders a link to include Firebug Lite for debugging JavaScript in Internet Explorer. # def include_firebug_lite javascript_include "http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js" end # Renders a partial into the current view. HTML partial names must be preceded with an underscore. # # == Rendering an HTML partial # # HTML partials are located in app/views. HTML view files can be Haml or ERB. # Haml is recommended and takes preference. HTML partials are named _filename.html.haml # or _filename.html.erb. # # render :partial => 'sidebar' # # will find app/views/_sidebar.html.haml or app/views/_sidebar.html.erb # and render its contents into the current view. # # Specify a full path to indicate a specific template. # # render :partial => 'sidebar.html.erb' # # will find app/views/_sidebar.html.erb' and render it even if # app/views/_sidebar.html.haml exists. # # render :partial => 'shared/sidebar' # # will find app/views/shared/_sidebar.html.haml and render its contents into the current view. # # == Rendering a JavaScript partial # # You can render a single JavaScript file or send an array to concatenate a set of JavaScript # files together asone script block. # # === Rendering a single JavaScript partial # # JavaScript partials are located in app/javascripts and are named filename.js # # render :javascript => 'application' # # will find app/javascripts/application.js and render its contents into the current view # in an inline script block. # # render :javascript => 'shared/sidebar' # # will find app/javascripts/shared/sidebar.js and render its contents into the current # view in an inline script block. # # == Rendering a stylesheet partial # # Stylesheets are located at app/stylesheets and are named _filename_.css # # # === Rendering multiple partials # # Pass an array to render to combine multiple files into a single # inline block. This is useful for compression and validation, as it allows a set of # files to be compressed or validated in a single context. # # render :javascript => ['application', 'flash', 'debug'] # # will combine the contents of app/javascripts/application.js, # app/javascripts/application.js, and app/javascripts/application.js # into a single script block in the current view. # # Pass a :filename parameter to set the name of the combined file. Currently the # combined file only exists on disc while it's being compressed and/or validated, but # in the future this may be expanded to save multiple files as a single external asset. # # render :javascript = ['application', 'flash', 'debug'], :filename => 'javascripts' # # Currently the :filename parameter is simply a convenience. # # Multiple partials of any type can be rendered. # # For example: # # render :partial => ['header', 'footer', 'sidebar'], :filename => 'html_layouts' # # will find app/views/_header.html.haml, app/views/_footer.html.haml, # and app/views/_sidebar.html.haml and write them to a temporary file called # tmp/html_layouts before rendering that file into the current view. # # This feature is intended mainly for JavaScript and CSS. # # For example: # # render :stylesheet => ['application', 'colors'], :filename => 'styles' # # will render app/stylesheets/application.css and app/stylesheets/colors.css # as a single temporary file called tmp/styles before rendering that file into # the current view. # # If compression and validation options are turned on, the resulting temporary file will be # compressed and/or validated before being rendered into the current view. This will result # in a more efficient compression and a more effective validation. # def render(params) output = [] unless params.has_key?(:tags) params[:tags] = true end output << render_html_partial(params) output << render_javascript_partial(params) if params[:javascript] output << render_stylesheet_partial(params) if params[:stylesheet] output.flatten.join("\n") end private # Renders an HTML, Haml or ERB partial. # def render_html_partial(params) output = [] if params[:partial] params[:partial].to_a.each do |partial| output << render_partial(partial) end end output end # Renders an HTML partial. # def render_partial(filename) output = '' path = find_partial(filename) if path && File.exists?(path) template = File.read(path) if path =~ /haml$/ output = process_haml(template, path) else output = process_template(template) end else raise "Could not find partial: #{filename}" end output end # Searches all the possible paths to find a match for this partial name. # def find_partial(full_path) path = nil ["views", "views/shared"].each do |dir| p = full_path.split("/") filename = p.pop filename = "_#{filename}" p.push(filename) final_path = p.join("/") basic_path = "#{BASE_PATH}/app/#{dir}/#{final_path}.html" ["", ".haml", ".erb"].each do |extension| if File.exists?(basic_path + extension) path ||= basic_path + extension end end end path end def render_javascript_partial(params) filename = params[:filename] || params[:javascript].to_a.join("_") if configuration.external_assets["javascripts"] tags = false else tags = params[:tags] end output = [] # Render a JavaScript partial. # if params[:javascript] content = render_javascripts(params[:javascript].to_a, params[:filename]) unless content.blank? output << "" if tags end end output if configuration.external_assets["javascripts"] && params[:tags] write_javascript_asset(output, filename) "" else output end end def write_javascript_asset(output, filename) path = "#{server_path}/assets/javascripts/#{filename}.js" $stdout.puts "Writing #{path}" File.open(path, "w") do |f| f.write(output) end end def write_stylesheet_asset(output, filename) path = "#{server_path}/assets/stylesheets/#{filename}.css" $stdout.puts "Writing #{path}" File.open(path, "w") do |f| f.write(output) end end # Renders a JavaScript partial. # def render_javascripts(filenames, combined_filename=nil) filenames_str = combined_filename || filenames.join() filenames.map! do |filename| filename.gsub!(/\.js$/, "") "#{BASE_PATH}/app/javascripts/#{filename}.js" end output = combine_files(filenames) tmp_filename = "#{TMP_PATH}/#{filenames_str}.js" validate = F.save_to_file(output, tmp_filename) output = Epic::Compressor.new(tmp_filename).compress if configuration.compress["embedded_js"] if validate && configuration.validate["embedded_js"]["build"] && !js_validator.validate(tmp_filename) raise "JavaScript Errors embedded in #{display_path(tmp_filename)}" end output end def js_validator @js_validator ||= Epic::Validator::JavaScript.new end # Render a CSS partial. # def render_stylesheet_partial(params) filename = params[:filename] || params[:stylesheet].to_a.join("_") external_asset = params[:tags] && configuration.external_assets["javascripts"] output = [] if params[:stylesheet] content = render_stylesheets(params[:stylesheet].to_a, params[:filename]) unless content.blank? output << "" unless external_asset end end if external_asset write_stylesheet_asset(output, filename) "" else output end end # Renders a JavaScript partial. # def render_stylesheets(filenames, combined_filename=nil) filenames_str = combined_filename || filenames.join() tmp_filename = "#{TMP_PATH}/#{filenames_str}.css" filenames.map! do |filename| filename.gsub!(/\.css$/, "") "#{BASE_PATH}/app/stylesheets/#{filename}.css" end output = combine_files(filenames) validate = F.save_to_file(output, tmp_filename) output = Epic::Compressor.new(tmp_filename).compress if configuration.compress["css"] output end # Concatenates all javascript files into one long string. # def combine_files(filenames) output = [] filenames.each do |filename| output << render_without_compression(filename, false) end output.join("\n") end # Renders together a set of JavaScript files without # compression, so they can be compressed as a single block. # def render_without_compression(path, tags=true) output = "" if File.exists?(path) template = File.read(path) output = process_template(template) end output end end class View include YMDP::ApplicationView def initialize(assets_directory) @assets_directory = assets_directory end end end