module Ramenu
module Menus
# The Builder class represents the abstract class for any custom Builder.
#
# To create a custom Builder, just extend this class
# and implement the following abstract methods:
#
# * #render: Renders and returns the collection of navigation elements
#
class Builder
# Initializes a new Builder with context,
# element and options.
#
# @param [ActionView::Base] context The view context.
# @param [Array] elements The collection of Elements.
# @param [Hash] options Hash of options to customize the rendering behavior.
#
def initialize(context, elements, options = {})
@context = context
@elements = elements
@options = options
end
# Renders Elements and returns the Breadcrumb navigation for the view.
#
# @return [String] The result of the menu rendering.
#
# @abstract You must implement this method in your custom Builder.
def render
raise NotImplementedError
end
# get flag associated to element
def flag_for(element, option = :flag)
flag = nil
flag_selector = element.options[option]
unless flag_selector.nil?
flag = @options[:flags][flag_selector] if @options[:flags].include?(flag_selector)
end
return flag
end
protected
def compute_name(element)
case name = element.name
when Symbol
begin
@context.send(name)
rescue NoMethodError
key = 'ramenu.menus.' + @options[:menu].to_s + element.translation_key
I18n.t(key)
end
when Proc
name.call(@context)
else
name.to_s
end
end
def compute_path(element)
case path = element.path
when Symbol
@context.send(path)
when Proc
path.call(@context)
when Hash
@context.url_for(path)
else
path.to_s
end
end
end
# The SimpleBuilder is the default menu builder.
# It provides basic functionalities to render a menu navigation.
#
# The SimpleBuilder accepts a limited set of options.
# If you need more flexibility, create a custom Builder and
# pass the option :builder => BuilderClass to the render_menus helper method.
#
class SimpleBuilder < Builder
def render
@elements.collect do |element|
render_element(element)
end.join(@options[:separator] || " » ")
end
def render_element(element)
content = @context.link_to_unless_current(compute_name(element), compute_path(element), element.options)
# rendering sub-elements
if (element.childs.length > 0)
content = content + " |"
element.childs.each do |child|
content = content + @context.link_to_unless_current(compute_name(child), compute_path(child)) + "|"
end
end
if @options[:tag]
@context.content_tag(@options[:tag], content)
else
content
end
end
end
# Represents a navigation element in the menu collection.
#
class Element
# @return [String] The element/link name.
attr_accessor :name
# @return [String] The element/link URL.
attr_accessor :path
# @return [Hash] The element/link childs
attr_accessor :childs
# @return [Element] The element/link parent
attr_accessor :parent
# @return [Hash] The element/link URL.
attr_accessor :options
# Initializes the Element with given parameters.
#
# @param [String] name The element/link name.
# @param [String] path The element/link URL.
# @param [Hash] options The element/link URL.
# @return [Element]
#
def initialize(name, path, options = {})
self.name = name
self.path = path
self.childs = []
#self.parent = @options[:parent]
self.parent = options.delete(:parent)
self.options = options
end
def translation_key
key = ''
elem = self
while !elem.nil? do
key = '.' + elem.name.to_s + key if elem.name.is_a?(Symbol)
key = '.' + elem.name.to_sym.to_s + key if elem.name.is_a?(String)
elem = elem.parent
end
key += '.root' if self.childs.count > 0
return key
end
def add_menu(name, path, options = {}, &block)
opts = options.merge({:parent => self})
self.childs << Ramenu.new_ramenu_element(name, path, opts, &block)
end
alias :add_child :add_menu
end
end
end