module Olelo class Menu include Util include Enumerable attr_reader :name def initialize(name) @name = name.to_sym @items = {} end def each(&block) @items.each_value(&block) end def [](name) path = path.to_s i = path.index('/') if i item = @items[path[0...i]] item[path[i+1..-1]] if item else @items[name.to_sym] end end def item(name, options = {}) self << MenuItem.new(name, options) end def append(items) items.each {|item| self << item } end def <<(item) raise TypeError, "Only items allowed" unless MenuItem === item raise "Item #{item.name} exists already in #{path.join('/')}" if @items.include?(item.name) item.parent = self @items[item.name] = item end def empty? @items.empty? end def clear @items.clear end def remove(name) path = name.to_s i = path.index('/') if i item = @items[path[0...i]] item.remove(path[i+1..-1]) if item else @items.delete(name.to_sym) end end def build_menu empty? ? '' : %{
} end def to_html build_menu.html_safe end def html_id escape_html path.join('-') end def path [name] end end class MenuItem < Menu attr_reader :options attr_accessor :parent def initialize(name, options = {}) super(name) @parent = nil @options = options end def path parent ? parent.path << super : super end def build_menu attrs = options.dup label = attrs.delete(:label) || Locale.translate("menu_#{path.join('_')}", fallback: titlecase(name)) klass = [*attrs.delete(:class)].flatten.compact klass = klass.empty? ? '' : %{class="#{klass.join(' ')}" } attrs = attrs.map {|k,v| %{#{k}="#{escape_html v}"} }.join(' ') %{