Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Jekyllによる複数レベルのサブナビゲーション

以前の投稿で、Jekyllページの各H2のサブナビゲーションリンクを生成する方法を示しました。この投稿では、その基盤の上に構築し、H3、H4などに基づいて任意のレベルのサブナビゲーションを追加する方法を示します。

概要

このプロジェクトをいくつかのステップに分けました:

  • まず、nokogiriを使用して、H2タグの「内側」にあるH3タグで定義されたセクションを引き出します
  • 次に、クールなトリックを使用して、任意のレベルのサブナビゲーションをレンダリングします。再帰的なテンプレートを作成します。

始める前に、何かを明確にしましょう。 H3タグをH2の内部にあると言うとき、それが文字通りネストされているという意味ではありません。代わりに、以下に示す状況を参照しています:

<h2>Animals</h2>
<p>Here are some kinds of animals.</p>
<h3>Giraffe</h3>
<p>This section about giraffes logically belongs inside of the section about animals, even though the structure of the Dom doesn't define it as being nested</p>
<h3>Zebra</h3>
<p>Another section that logically belongs under "Animals"</p>
ドキュメントをセクションに分割する

上記のようなHTMLドキュメントをセクションに分割するときに直面する明らかな問題は、何もネストされていないことです。 HTMLを解析するためのツールのほとんどは、ネストで機能するように構築されています。

これは取引を妨げるものではありませんが、もう少し作業を行う必要があることを意味します。以下の例では、各H2タグを見つけてから、兄弟を手動でスキャンしてH3タグを探します。

私は空想を得て、カスタム列挙子を使用しました。それらについて質問がある場合は、それらに関する私のブログ投稿をチェックしてください。

require "nokogiri"

class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    parser = Jekyll::Converters::Markdown.new(site.config)

    site.pages.each do |page|
      if page.ext == ".md"
        doc = Nokogiri::HTML(parser.convert(page['content']))

        page.data["subnav"] = doc.css('h2').map do |h2|
          to_nav_item(page, h2).tap do |item|
            item["children"] = subheadings(h2).map { |h3| to_nav_item(page, h3) }
          end
        end
      end
    end
  end

  # Converts a heading into a hash of the info for a link
  def to_nav_item(page, heading)
    {
      "title" => heading.text,
      "url" => [page.url, heading['id']].join("#")
    }
  end

  # Returns an enumerator of all H3s "belonging" to an H2
  def subheadings(el)
    Enumerator.new do |y|
      next_el = el.next_sibling
      while next_el && next_el.name != "h2"
        if next_el.name == "h3"
          y << next_el
        end
        next_el = next_el.next_sibling
      end
    end
  end
end

これはあなたに投げかけるコードの塊であると私は理解していますが、それは以前の投稿で行った作業から構築されています。 Jekyllプラグインの構造や、nokogiriの使用方法について質問がある場合は、その記事を確認してください。

ドキュメントサイトに対してこのコードを実行すると、次のようなハッシュが表示されます。

[{"title"=>"Getting Started",
  "url"=>"/lib/java.html#getting-started",
  "sub_subnav"=>
   [{"title"=>"Download / Maven", "url"=>"/lib/java.html#download-maven"},
    {"title"=>"Stand Alone Usage", "url"=>"/lib/java.html#stand-alone-usage"},
    {"title"=>"Servlet Usage", "url"=>"/lib/java.html#servlet-usage"},
    {"title"=>"Play Usage", "url"=>"/lib/java.html#play-usage"},
    {"title"=>"API Usage", "url"=>"/lib/java.html#api-usage"}]},
    ...

今やらなければならないのは、液体テンプレートを使用してこれをレンダリングする方法を理解することだけです。

サブナビのレンダリング

リキッドテンプレートを使用して任意の深さのサブナビゲーションをレンダリングすることは、実際にはそれほど難しくありません。秘訣は、それ自体をレンダリングするパーシャルを使用することです。

私のレイアウトでは、部分をレンダリングして、ナビゲーションアイテムのコレクションを渡します。

{% include navigation_item.html collection=page.subnav level=0 %}

パーシャルは、このレベルのナビゲーションのリンクを作成してから、それ自体をレンダリングして、子のリストを渡します。再帰関数と同じように、これは理論的には永遠に続く可能性があります。キックのためだけに、subnavの各レベルにlevel-1のようなクラスを与えるためのコードを少し追加しました またはlevel-2 。これはスタイリングに非常に役立ちます。

{% if include.collection.size > 0 %}
<ul class="nav nav-list level-{{ include.level }}">
    {% for item in include.collection %}
      {% if item.url == page.url %}
      <li class="active">
      {% else %}
      <li>
      {% endif %}
        {% if item.subnav.size > 0 %}
          <a class="has-subnav" href="{{ item.url }}">
          <span class="glyphicon glyphicon-plus"></span>
          <span class="glyphicon glyphicon-minus"></span>
        {% else %}
          <a href="{{ item.url }}">
        {% endif %}
          {{ item.title }}
        </a>
        {% assign next_level = include.level | plus: 1 %}
        {% include navigation_item.html collection=item.children level=next_level %}
      </li>
    {% endfor %}
  </ul>
{% endif %}

以上です!

これで、ジキルの素晴らしい世界への簡単な進出は終わりです。 Rubyの内部に関する一連の記事を公開してから数日が経ちますので、ご期待ください。


  1. Androidで複数の画面でWebビューをサポートするにはどうすればよいですか?

    この例は、Androidで複数の画面を使用してWebビューをサポートする方法について示しています。 ステップ1 − Android Studioで新しいプロジェクトを作成し、[ファイル]⇒[新しいプロジェクト]に移動して、新しいプロジェクトを作成するために必要なすべての詳細を入力します。 ステップ2 −次のコードをres / layout/activity_main.xmlに追加します。 <?xml version = "1.0" encoding = "utf-8"?> <LinearLayout xmlns:android =

  2. CSS3で複数の背景を追加する

    複数の背景を追加するには、CSSのbackground-imageプロパティを使用します。以下は、複数の背景を追加するためのコードです- 例 <!DOCTYPE html> <html> <head> <style> body {    font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; } div {    background-image:    url("https://pngimg