Change anchor tags for sections to be based on the titles, not randomly generated (#288)

* Change anchor tags for sections to be based on the titles, not randomly generated

* Update lib/livebook_web/helpers.ex

Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
Brian Underwood 2021-05-23 18:22:55 +02:00 committed by GitHub
parent e10f43e5b5
commit 8dfe12da68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 9 deletions

View file

@ -86,4 +86,32 @@ defmodule LivebookWeb.Helpers do
pid_str = Phoenix.LiveDashboard.Helpers.encode_pid(pid)
Routes.live_dashboard_path(socket, :page, node(), "processes", info: pid_str)
end
@doc """
Converts human-readable strings to strings which can be used
as HTML element IDs (compatible with HTML5)
At the same time duplicate IDs are enumerated to avoid duplicates
"""
@spec names_to_html_ids(list(String.t())) :: list(String.t())
def names_to_html_ids(names) do
names
|> Enum.map(&name_to_html_id/1)
|> Enum.map_reduce(%{}, fn html_id, counts ->
counts = Map.update(counts, html_id, 1, &(&1 + 1))
case counts[html_id] do
1 -> {html_id, counts}
count -> {"#{html_id}-#{count}", counts}
end
end)
|> elem(0)
end
defp name_to_html_id(name) do
name
|> String.trim()
|> String.downcase()
|> String.replace(~r/\s+/u, "-")
end
end

View file

@ -737,7 +737,7 @@ defmodule LivebookWeb.SessionLive do
data.clients_map
|> Enum.map(fn {client_pid, user_id} -> {client_pid, data.users_map[user_id]} end)
|> Enum.sort_by(fn {_client_pid, user} -> user.name end),
section_views: Enum.map(data.notebook.sections, &section_to_view(&1, data))
section_views: section_views(data.notebook.sections, data)
}
end
@ -768,12 +768,19 @@ defmodule LivebookWeb.SessionLive do
defp evaluated?(cell, data), do: data.cell_infos[cell.id].validity_status == :evaluated
defp section_to_view(section, data) do
%{
id: section.id,
name: section.name,
cell_views: Enum.map(section.cells, &cell_to_view(&1, data))
}
defp section_views(sections, data) do
sections
|> Enum.map(& &1.name)
|> names_to_html_ids()
|> Enum.zip(sections)
|> Enum.map(fn {html_id, section} ->
%{
id: section.id,
html_id: html_id,
name: section.name,
cell_views: Enum.map(section.cells, &cell_to_view(&1, data))
}
end)
end
defp cell_to_view(cell, data) do

View file

@ -4,7 +4,7 @@ defmodule LivebookWeb.SessionLive.SectionComponent do
def render(assigns) do
~L"""
<div
id="section-<%= @section_view.id %>"
id="<%= @section_view.html_id %>"
data-element="section"
data-section-id="<%= @section_view.id %>">
<div class="flex space-x-4 items-center" data-element="section-headline">
@ -21,7 +21,7 @@ defmodule LivebookWeb.SessionLive.SectionComponent do
because we want the content to exactly match section name. %>
<div class="flex space-x-2 items-center" data-element="section-actions">
<span class="tooltip top" aria-label="Link">
<a href="#section-<%= @section_view.id %>" class="icon-button">
<a href="#<%= @section_view.html_id %>" class="icon-button">
<%= remix_icon("link", class: "text-xl") %>
</a>
</span>

View file

@ -12,4 +12,59 @@ defmodule LivebookWeb.HelpersTest do
Helpers.ansi_to_html_lines("\e[34msmiley\ncat\e[0m")
end
end
describe "names_to_html_ids/1" do
test "title case" do
assert(Helpers.names_to_html_ids(["Title of a Section"]) == ["title-of-a-section"])
end
# Contains a couple of unicode spaces to ensure that we handle those
test "space characters" do
assert Helpers.names_to_html_ids([" slug \n with spaces \t "]) == ["slug-with-spaces"]
end
test "emoji at end" do
assert Helpers.names_to_html_ids(["Test 🦦 "]) == ["test-🦦"]
end
test "emoji in middle" do
assert Helpers.names_to_html_ids(["One 🥮 Two"]) == ["one-🥮-two"]
end
test "returns empty list for an empty list" do
assert Helpers.names_to_html_ids([]) == []
end
test "returns id-ified strings for different kinds of names" do
names = [
"Title of a Section",
" something with \n many space characters \t "
]
assert Helpers.names_to_html_ids(names) == [
"title-of-a-section",
"something-with-many-space-characters"
]
end
test "enumerates ids when they would be the same" do
names = [
"Title of a Section",
"Some other title",
" Title of a Section",
"random",
" Title of a section",
"Title of a Section "
]
assert Helpers.names_to_html_ids(names) == [
"title-of-a-section",
"some-other-title",
"title-of-a-section-2",
"random",
"title-of-a-section-3",
"title-of-a-section-4"
]
end
end
end