I’d like to add HTML content to rendered web pages. My current use case is a table of contents (TOC), listing (and linking to) each of the page’s headings. Here’s some science fiction for a possible approach:
- grab the output of
Phoenix.View.render/3
- turn the IO List into a single binary string
- extract the heading levels and text content
- generate the TOC (e.g., an HTML list of links)
- add the TOC and anchors to the page’s HTML
- turn it all back into an IO List
Problem is, I’m not sure about the best way to grab render
's output. Should I override render
in some manner, pipe its output into another function, use a pipe_through
in router.ex
, or what? Suggestions welcome…
I’m probably misunderstanding your problem, but wouldn’t it be easier to write a module with functions containing the headings with links and use them both in the pages and in the ToC?
defmodule Headings do
# not sure it would work
titles_for_routes = %{
Routes.page_path(YourWeb.Endpoint, :index) => "This is the Index PAGE",
# ...
}
Enum.map(titles_for_routes, fn {route, title} ->
def title(unquote(route)), do: unquote(title)
end)
def title(_unmatched), do: "Some default title"
end
# on the page
<title><%= Headings.title(@conn.private[:phoenix][:route]) # or whereever phoenix stores it's current route %></title>
# in the toc
<ul>
<%= Enum.map(@routes, fn route -> %>
<li><%= link(Headings.title(route), to: route) %></li>
<% end) %>
</ul>
1 Like
Thanks for the thoughtful and detailed reply. The problem with this approach, in my case, is that I have a number of places and ways in which headings are generated. For example:
- Some headings are hard-wired into the templates.
- Some headings are generated automagically, along with page sections, if the relevant data is available.
- Some headings are encoded in Markdown source code.
Because I’d rather not couple the TOC generation to each of these spots in the code, I’m thinking about a post-processing approach: if there’s a heading in the resulting HTML, I index it.
Here are some links that may help to show what’s going on:
1 Like