Frage

I have a page that is formatted like so:

<h1>Header</h1>
<h2>Subheader</h2>    
<h3>Subsubheader</h3>
<h1>Another header</h1>

Is it possible to server-side generate a table of contents / outline at the start of the page, like Wikipedia does in its articles? I use Ruby on Rails.

EDIT: WITHOUT JavaScript!

War es hilfreich?

Lösung 2

You need to generate data source from your hierarchy to be something like this

 @toc = [ ['header', 0], ['subheader', 1], ['subsubheader', 2],
             ['header2', 0], ['header3', 0], ['subheader2', 1]
        ]

Than it is easy to render it in template, for example:

<%- @toc.each do |item, distance| %>
    <%= ('&nbsp;' * distance  * 5).html_safe %>
    <%= item %>
    <br/>
<%- end %>

Would give you:

header 
      subheader 
           subsubheader 
header2 
header3 
      subheader2 

Of course you can use 'distance' for determining style size instead of 'depth', but I hope you get the main idea.

Andere Tipps

I created a class for this purpose today. It depends on http://www.nokogiri.org/, but that gem comes with Rails already.

Put this in app/models/toc.rb:

class Toc
  attr_accessor :html

  TOC_CLASS = "toc".freeze
  TOC_ELEMENT = "p".freeze
  TOC_ITEMS = "h1 | h2 | h3 | h4 | h5".freeze
  UNIQUEABLE_ELEMENTS = "h1 | h2 | h3 | h4 | h5 | p".freeze

  def initialize(content)
    @html = Nokogiri::HTML.fragment content
  end

  def generate
    clear
    set_uniq_ids
    toc = create_container

    html.xpath(TOC_ITEMS).each { |node| toc << toc_item_tag(node) }
    html.prepend_child toc

    return html.to_s
  end

  private

  def clear
    html.search(".#{TOC_CLASS}").remove
  end

  def set_uniq_ids
    html.xpath(UNIQUEABLE_ELEMENTS).
      each { |node| node["id"] = rand_id }
  end

  def rand_id
    (0...8).map { ('a'..'z').to_a[rand(26)] }.join
  end

  def create_container
    toc = Nokogiri::XML::Node.new TOC_ELEMENT, html
    toc["class"] = TOC_CLASS

    return toc
  end

  def toc_item_tag(node)
    "<a data-turbolinks='false' class=\"toc-link toc-link-#{node.name}\" href=\"##{node["id"]}\">#{node.text}</a>"
  end
end

Use it like

toc = Toc.new article.body
body_with_toc = toc.generate
article.update body: body_with_toc

yes, it is possible. you don't really need rails for this; you can also use javascript to generate a table of contents. Here is an exmaple library that you can use. http://www.kryogenix.org/code/browser/generated-toc/

You could alternatively create your anchor links as you loop through elements in your rails erb/haml views.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top