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 플러그인의 구조나 노코기리 사용 방식에 대해 궁금한 점이 있으면 해당 기사를 확인하세요.

문서 사이트에 대해 이 코드를 실행하면 다음과 같은 해시가 표시됩니다.

[{"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 %}

partial은 이 탐색 수준에 대한 링크를 만든 다음 자체적으로 렌더링하여 자식 목록을 전달합니다. 재귀 함수와 마찬가지로 이것은 이론적으로 영원히 계속될 수 있습니다. 간단하게 level-1과 같은 subnav 클래스의 각 수준을 제공하는 약간의 코드를 추가했습니다. 또는 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 내부에 대한 일련의 기사가 게시될 예정이니 계속 지켜봐 주시기 바랍니다!