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