Как построить вложенное меню "деревья" в HAML - PullRequest
4 голосов
/ 11 марта 2010

Я пытаюсь создать простое вложенное html-меню, используя HAML, и я не уверен, как выполнить вставку элементов с правильным отступом или вообще лучшим способом построения вложенных деревьев. Я хотел бы иметь возможность сделать что-то вроде этого, но бесконечно глубоко:

- categories.each_key do |category|
    %li.cat-item{:id => "category-#{category}"}
        %a{:href => "/category/#{category}", :title => "#{category.titleize}"}
            = category.titleize

Такое чувство, что я мог бы довольно легко выполнить это, не прибегая к написанию тегов вручную в html, но я не лучший в рекурсии. Вот код, который я сейчас придумала:

Просмотр помощника

def menu_tag_builder(array, &block)
  return "" if array.nil?
  result = "<ul>\n"
  array.each do |node|
    result += "<li"
    attributes = {}
    if block_given?
      text = yield(attributes, node)
    else
      text = node["title"]
    end
    attributes.each { |k,v| result += " #{k.to_s}='#{v.to_s}'"}
    result += ">\n"
    result += text
    result += menu_tag_builder(node["children"], &block)
    result += "</li>\n"
  end
  result += "</ul>"
  result
end

def menu_tag(array, &block)
  haml_concat(menu_tag_builder(array, &block))
end

View

# index.haml, where config(:menu) converts the yaml below
# to an array of objects, where object[:children] is a nested array
- menu_tag(config(:menu)) do |attributes, node|
 - attributes[:class] = "one two"
 - node["title"]

Пример меню, определяющего YAML

menu:
  -
    title: "Home"
    path: "/home"
  -
    title: "About Us"
    path: "/about"
    children: 
      -
        title: "Our Story"
        path: "/about/our-story"

Любые идеи, как это сделать, чтобы вывод был таким:

<ul>
  <li class='one two'>
    Home
  </li>
  <li class='one two'>
    About Us
  </li>
</ul>

... не так:

<ul>
<li class='one two'>
Home</li>
<li class='one two'>
About Us</li>
</ul>

... и поэтому он имеет глобальный отступ.

Спасибо за помощь, Lance

Ответы [ 4 ]

5 голосов
/ 11 марта 2010

Хитрость хорошо скомпонованного, сгенерированного Ruby кода Haml - это haml_tag помощник . Вот как я бы преобразовал ваш menu_tag метод в haml_tag:

def menu_tag(array, &block)
  return unless array
  haml_tag :ul do
    array.each do |node|
      attributes = {}
      if block_given?
        text = yield(attributes, node)
      else
        text = node["title"]
      end
      haml_tag :li, text, attributes
      menu_tag_builder(node["children"], &block)
    end
  end
end
3 голосов
/ 06 января 2012

Как насчет чего-то вроде:

def nested_list(list)
  return unless list
  haml_tag :ul do
    list.each do |item|
      haml_tag :li do
        haml_concat link_to item["title"], item["path"]
        if item["children"]
          nested_list item["children"]
        end
      end
    end
  end
end
0 голосов
/ 11 марта 2010

Круто, подсказка @ shingara направила меня в правильном направлении :). Это прекрасно работает:

def menu_tag(array, &block)
  return "" if array.nil?
  haml_tag :ui do
    array.each do |node|
      attributes = {}
      if block_given?
        text = yield(attributes, node)
      else
        text = node[:title]
      end
      haml_tag :li, attributes do
        haml_concat text
        menu_tag_builder(node[:children], &block)
      end
    end
  end
end

Если кто-то может сделать это еще короче или упростить настройку атрибутов на вложенных узлах, я отмечу это как правильное вместо этого.

Приветствие.

0 голосов
/ 11 марта 2010

Это потому что вы отправляете чистый HTML вашим помощником. Отступы делаются с HAML. Вы можете создать HAML в вашем помощнике.

...