Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Deep Dive: สร้าง Multi-Level Subnavigation ใน Jekyll

โพสต์ก่อนแสดง generate subnavigation links สำหรับ H2 แต่ละตัวใน Jekyll page โพสต์นี้ build บน foundation นั้น เพิ่ม arbitrary levels of subnavigation จาก H3, H4 ฯลฯ

Overview

แยก project เป็น steps:

  • First, 用 nokogiri ดึง sections ที่ H3 tags define "inside" H2 tags
  • Next, 用 cool trick render arbitrary levels sub navigation: recursive template

ก่อนเริ่ม ทำชัด: เวลาพูด H3 tag inside H2 ไม่ได้หมายถึง nested literally แต่ situation ด้านล่าง:


Animals

Here are some kinds of animals.

Giraffe

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

Zebra

Another section that logically belongs under "Animals"

Breaking the Document into Sections

Problem 明顯 breaking HTML document เหมือนข้างบนเป็น sections: nothing is nested tools parse HTML ส่วนใหญ่ built for nesting

ไม่ phải deal breaker แต่ทำงานเพิ่ม ตัวอย่างหา H2 tags แล้ว manually scan siblings หา H3 tags

用 custom enumerator คำถามเกี่ยว enumerators ดู blog post เกี่ยวพวกมัน


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

  # Convert heading เป็น hash ข้อมูล link
  def to_nav_item(page, heading)
    { "title" => heading.text, "url" => [page.url, heading['id']].join("#") }
  end

  # คืน enumerator ของ H3s ทั้งหมด "belonging" ให้ 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

รู้ว่า code blob ใหญ่แต่มาจาก previous post ถ้ามีคำถามโครงสร้าง Jekyll plugins หรือ nokogiri usage ดู article นั้น

รัน code ต่อ documentation site ได้ hash ประมาณนี้:


[{"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"}
]}, ... ]

ตอนนี้ render ด้วย liquid templates

Rendering the Subnav

Render arbitrarily deep sub navigation ด้วย liquid templates ไมยาก Trick: 用 partial ที่ render ตัวเอง

ใน layout render partial ส่ง collection navigation items:


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

Partial สร้าง links สำหรับ level นี้ แล้ว render ตัวเอง ส่ง children list เหมือน recursive function idealistically forever เพื่อสนุกเพิ่ม code ให้แต่ละ level subnav class เช่น level-1 หรือ level-2 useful สำหรับ styling


{% if include.collection.size > 0 %}

{% endif %}

That's it!

จบ foray สั้นๆ Jekyll world ในวันๆ จะ publish series articles Ruby internals stay tuned!