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

สร้าง Jekyll Plugin Auto-Generate Subnav จาก H2 Headings

สร้าง Jekyll Plugin Auto-Generate Subnav จาก H2 Headings

กำลัง rebuild documentation site ด้วย Jekyll เนื่องจาก documentation pages ใหญ่ ต้องมี subnavigation เพิ่มจาก top-level navigation

โพสต์นี้ครอบคลุมทำ Jekyll plugin 簡單 generate subnav links จาก headings ใน posts หรือ pages

Overview

แยก project เป็น tasks:

  1. สร้าง Jekyll generator รันทุก page บน site
  2. สอน generator pre-render pages เพื่อ extract heading information
  3. 用 nokogiri parse HTML หา relevant headings และ content
  4. Render subnavigation

ในตัวอย่าง subnav links ทั้งหมดเป็น anchor links approach นี้ต้องการ markdown processor สร้าง IDs ให้ headings RedCarpet กับ option with_toc_data ใช้งานดี

Basic Jekyll Generator

มี plugin types หลาย種 สร้าง generator

Generators คือ classes inherit Jekyll::Generator มี method generate

Generators รันหลัง Jekyll load markdown files ทั้งหมด แต่ก่อน convert เป็น HTML object site ส่งเข้า generate method 用 site object เข้าถึง pages, posts, resources ทั้งหมด

ตัวอย่าง generator loop ทุก pages พิมพ์ titles:


class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    site.pages.each do |page|
      puts page.data["title"]
    end
  end
end

修改 page และ site data ใน generator ได้ data จาก front-matter และ site config


page.data["title"] += " - modified!"
site.data["tagline"]

Pre-Rendering Markdown to HTML

อยาก extract headings จาก markdown documents 简单方式: convert markdown เป็น HTML แล้ว parse HTML 用 nokogiri

Covert มากับ dirty? ใช่ จะช้า? แน่นอน แต่ Jekyll static site generator ไม่ต้องกังวล real-time performance แค่จมูกได้

用 Jekyll built-in markdown wrapper convert markdown pages ทุกตัวเป็น HTML:


class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    parser = Jekyll::Converters::Markdown.new(site.config)
    site.pages.each do |page|
      if page.ext == ".md"
        html = parser.convert(page['content'])
        # Do something with the html here
      end
    end
  end
end

Extracting Headings

Documentation site ใหม่ decide ทุก H2 tag ควรมี subnavigation link 用 nokogiri parse HTML แต่ละ page ดึง H2 tags ทุกตัว

ตอนนี้แค่ print H2 content และ ID หน้าจอ:


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']))
        doc.css('h2').each do |heading|
          puts "#{ heading.text }: #{ heading['id'] }"
        end
      end
    end
  end
end

Creating the Subnavigation Menu

ตอนมี headings text และ ID สร้าง list subnavigation links

เก็บ list links เป็น data attribute ของ page เอง เข้าถึง links จาก page template ได้


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').each do |heading|
          page.data["subnav"] << { "title" => heading.text, "url" => [page.url, heading['id']].join("#") }
        end
      end
    end
  end
end

ตอนนี้ใน template loop subnav แสดงแต่ละ link:


{% for item in page.subnav %}
  {{ item.title }}
{% endfor %}

Troubleshooting

เหมือนกล่าว ขึ้นกับ markdown processor สร้าง unique IDs ให้ headings markdown settings จาก _config.yml:


# Use the redcarpet Markdown renderer
markdown: redcarpet
redcarpet:
  extensions: [ 'no_intra_emphasis', 'fenced_code_blocks', 'autolink', 'strikethrough', 'superscript', 'with_toc_data', 'tables', 'hardwrap' ]

Next Up...

Approach ข้างบน work ดีถ้าต้องการ one level subnavigation แตถ้าต้องการมากกว่า? เช่น H3 tags "inside" H2 สร้าง sub-subnavigation links ใน menu?

จะครอบคลุมใน future blog post stay tuned!