# Methods added to this helper will be available to all templates in the application.
require "RMagick"
module ApplicationHelper
include Magick
def title(text)
content_for(:title, content_tag(:title, text + ": Mildred"))
end
def dequeue
html = content_tag(:div, :id => "dequeue") do
attributes = {
:alt => "Working...",
:id => "dequeue_indicator",
:style => "display: none;",
}
image_tag("indicator.gif", attributes) +
content_tag(:span, :id => "dequeue_text") {"Dequeue"}
end
options = {
:accept => "de",
:hoverclass => "hover_class",
:onDrop => "QUEUE.Dequeue.bind(QUEUE)",
}
html << drop_receiving_element("dequeue", options)
end
def requests
html = content_tag(:div, :id => "requests") do
attributes = {
:alt => "Working...",
:id => "requests_indicator",
:style => "display: none;",
}
image_tag("indicator.gif", attributes) +
content_tag(:span, :id => "requests_text") {"Drag requests here."}
end
options = {
:accept => "tr",
:hoverclass => "hover_class",
:onDrop => "QUEUE.Request.bind(QUEUE)",
}
html << drop_receiving_element("requests", options)
html << content_tag(:div, :class => "xx-small") {"* indicates a request"}
end
def queue_history
content_tag(:ul, :id => "history") do
render :partial => "/shared/playlist_track_history",
:collection => @playlist[:history]
end
end
# TODO rename me?
def limit_string(s, lim)
return h(s) unless s.size >= lim
# remove the last 3 chars to make room for the ellipsis
h(s[0..(lim-3)]) + "…"
end
def classify_media(media)
classes = {
:cds => [],
:internet => false,
}
media.each do |medium|
case medium.medium
when "CD3", "CD5": classes[:cds] << medium.format
when "Internet": classes[:internet] = true
end
end
classes
end
def build_media_text(classes)
text = []
if classes[:cds].size > 1
text << "#{classes[:cds].size}×CD"
elsif classes[:cds].size == 1
text << classes[:cds].first
end
if classes[:internet]
text << "Internet"
end
text
end
def album_format(album)
classes = classify_media(album.media)
text = build_media_text(classes)
if text.empty?
logger.debug("No media found of which to report the format")
return "?"
else
return text.join(", ")
end
end
def divide_objects(objects)
half = (objects.size / 2.0).ceil
left = objects.slice(0, half)
right = objects.slice(half, objects.size - half)
[left, right]
end
def format_last_played(time)
now = Time.new
if time.nil? || time == Time.at(0)
return "?"
elsif time >= now.midnight
return "Today at #{time.strftime("%I:%M %p")}."
elsif time >= now.yesterday.midnight
return "Yesterday at #{time.strftime("%I:%M %p")}."
elsif time >= now.last_month
return time_ago_in_words(time).capitalize + " ago."
else
return "More than a month ago."
end
end
# return the track time as a string in hour:min:sec formatting.
def formatted_time(time)
hours = minutes = seconds = 0
hours = time / 1.hour
time -= hours * 1.hour
minutes = time / 1.minute
time -= minutes * 1.minute
seconds = time
if hours > 0
return sprintf("%d:%02d:%02d", hours, minutes, seconds)
else
return sprintf("%01d:%02d", minutes, seconds)
end
end
# TODO refactor me to take an argument, instead of relying on an instance var?
def get_title
@title.nil? ? "Mildred" : "#{@title} - Mildred"
end
def logged_in?
!session[:user_id].nil?
end
def current_user
@controller.send(:current_user)
end
# TODO refactor me and playlist_track
def playlist_track_queue_id(track, counter)
classes = ["playlist_track_queue_li"]
classes << "de" if logged_in?
track_id = "li_#{track.id}-#{counter}"
html = content_tag(:li, :id => track_id, :class => classes.join(" ")) do
playlist_track(track)
end
if !current_user.has_perm?(:reorder) && current_user.has_perm?(:dequeue)
options = {
:constraint => "\"vertical\"",
:ghosting => false,
:handle => "\"cropped\"",
:revert => true,
}
html << draggable_element("li_#{track.id}_#{counter}", options)
end
return html
end
# TODO refactor me and playlist_track_queue_id
def playlist_track(track, now_playing=false)
if track.nil?
render :partial => "/mildred/playlist_track_nil"
return
end
opts = []
# debugger
path = track_path(track)
time = track.last_played
time ||= Time.now
if !@playlist[:queue].index(track).nil?
np = @playlist[:now_playing]
pl_size = @playlist[:queue].size
np_lp = np ? np.last_played : Time.now
time = np ? np_lp + np.time.to_f : np_lp + Track.average(:time)
@playlist[:queue].each do |tr|
break if tr == track
time += tr.time.to_f
end
opts << " onclick=\"return check_for_drag_n_drop()\""
end
opts << " accesskey=\" \"" if track == @playlist[:now_playing]
opts << " onmouseover=\"show_track_details(this)\""
opts << " onmouseout=\"hide_track_details(this)\""
render :partial => "/shared/playlist_track",
:locals => {:track => track, :time => time,
:url => path, :opts => opts}
end
def rating_graph(rating)
rating = sprintf("%0.1f", rating.to_f).to_f
r = content_tag("span", "#{rating > 0 ? rating : "?"}/10") + " "
r += image_tag("pixel-grey.png", :style => "width: #{rating*(MINI_GRAPH_WIDTH_EM/10.0)}em", :class => "graph left", :alt => "small graph")
if rating < 10
r += image_tag("pixel-white.png", :style => "width: #{MINI_GRAPH_WIDTH_EM - (rating*(MINI_GRAPH_WIDTH_EM/10))}em", :class => "graph right", :alt => "small graph")
end
r
end
def rank_graph(rank, count)
r = content_tag("span", rank) + " "
r += image_tag("pixel-grey.png", :style => "width: #{MINI_GRAPH_WIDTH_EM - (rank.to_i*(MINI_GRAPH_WIDTH_EM/count))}em", :class => "graph left")
if rank.to_i > 1
r += image_tag("pixel-white.png", :style => "width: #{rank.to_i*(MINI_GRAPH_WIDTH_EM/count)}em", :class => "graph right")
end
r
end
def histogram(size, count)
grey_width = size * (HISTOGRAM_WIDTH_EM / count)
white_width = HISTOGRAM_WIDTH_EM - grey_width
r = image_tag("pixel-grey.png",
:style => "width: #{grey_width}em",
:class => "graph left")
r << image_tag("pixel-white.png",
:style => "width: #{white_width}em",
:class => "graph right")
end
def smart_quote(text)
"“#{text}”"
end
def album_thumb(album, opts={})
if album.art.size.zero? # we're going to get the default image
title = "No album art"
alt = "No image available"
path = "noimage.png"
else
title = h(album.title)
alt = "Album art: #{title}"
path = album.art[rand(album.art.size)].public_filename("t")
end
opts.reverse_merge!(:class => "thumb_img", :alt => alt, :title => title)
image_tag(path, opts)
end
def artist_thumb(artist, opts={})
if artist.art.size > 0
title = h(artist.name)
alt = "Artist image: #{title}"
path = artist.art[rand(artist.art.size)].public_filename("t")
# elsif artist.image_urls.size > 0
# title = h(artist.name)
# alt = "Artist image: #{title}"
# path = artist.image_urls[rand(artist.image_urls.size)]
else
title = "No artist art"
alt = "No image available"
path = "noimage.png"
end
opts.reverse_merge!(:class => "thumb_img", :alt => alt, :title => title)
image_tag(path, opts)
end
def link_to_album(album, options=Hash.new)
options = {:title => "Album: #{album.title}"}.merge(options)
options = {:class => "album_title"}.merge(options)
link_to(h(album.title), album_path(album), options)
end
def link_to_artist(artist, options=Hash.new)
options = {:title => "Artist: #{artist.name}"}.merge(options)
link_to(h(artist.name), artist_path(artist), options)
end
def link_to_mood(mood, options=Hash.new)
options = {:title => "Mood: #{mood.name}"}.merge(options)
link_to(h(mood.name), mood_path(mood), options)
end
def rating_slider(playlist, value)
if value < playlist[:now_playing].rating.to_i
classes = "current"
elsif value == playlist[:now_playing].rating.to_i
classes = "current last"
else
classes = ""
end
"<span onmouseover=\"slider_set(this, true)\" " <<
"onmouseout=\"slider_set(this, false)\" " <<
"class=\"#{classes}\" " <<
"onclick=\"report_rating(this, #{playlist[:now_playing].id})\">" <<
" \n \n</span>"
end
def google_image_search(*keywords)
args = URI.escape("\"" + keywords.join("\" \"") + "\"")
link_to("Google Image Search",
"http://images.google.com/images?q=#{args}",
{:target =>"new",})
end
def image_dimensions(path)
i = Image.read(RAILS_ROOT + "/public/images/" + path).first
"#{i.columns}x#{i.rows}"
end
# Takes an array of objects and returns a hash of the first occurrance of
# each first letter from the objects's specified method.
def generate_alpha_indices(objects, method)
links = {}
prev_letter = nil
objects.each_with_index do |obj, index|
first_letter = obj.send(method)[0..0].upcase
unless /[A-Z]/ === first_letter
first_letter = "#"
end
if first_letter != prev_letter
links[first_letter] = index
prev_letter = first_letter
end
end
links
end
def plus_minus_toggle(id)
link_to_function(content_tag(:span, "[-]", :id => id + "_toggler")) do |page|
page[id].toggle
page << "if (Element.visible('#{id}')) {$('#{id}_toggler').update('[-]')} else {$('#{id}_toggler').update('[+]')}"
end
end
# note that this method is generally destructive, and not general-purpose
def throbber(id, image)
"$('#{id}').update('#{image_tag(image)}');"
end
def update_queue(page)
page.replace_html(:playlist, :partial => "/shared/playlist")
if current_user.has_perm?(:rate) && page["rating_block"]
page.replace_html(:rating_block, :partial => "/shared/rating_slider")
end
end
def handle_follow_mode(page)
begin
if session[:last_played_track_id] != @playlist[:now_playing].id
session[:last_played_track_id] = @playlist[:now_playing].id
page.redirect_to(track_path(@playlist[:now_playing]))
end
rescue
logger.error("Error handling follow mode: #{$!}\n#{$!.backtrace.join("\n")}")
end
end
end