โพสต์ก่อนแสดง 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!