Skip to content

Commit 639afcc

Browse files
committed
Allow listing outside URLs in extras
This makes it possible to delcare URLs as extras and have them listed as links in the sidebar. For example, to set a "Wikipedia" url: ```elixir extras: [ "Wikipedia": [url: "https://wikipedia.com"] ] ``` Closes #2084
1 parent 38485a1 commit 639afcc

File tree

7 files changed

+96
-51
lines changed

7 files changed

+96
-51
lines changed

assets/js/sidebar/sidebar-list.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export function initialize () {
5959
const items = []
6060
const hasHeaders = Array.isArray(node.headers)
6161
const translate = hasHeaders ? undefined : 'no'
62+
const href = node?.url || `${node.id}.html`
6263

6364
// Group header.
6465
if (node.group !== group) {
@@ -78,7 +79,7 @@ export function initialize () {
7879
}
7980

8081
items.push(el('li', {}, [
81-
el('a', {href: `${node.id}.html`, translate}, [node.nested_title || node.title]),
82+
el('a', {href: href, translate}, [node.nested_title || node.title]),
8283
...childList(`node-${node.id}-headers`,
8384
hasHeaders
8485
? renderHeaders(node)

formatters/html/dist/html-5PS32TPG.js formatters/html/dist/html-AG646WP7.js

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ex_doc/formatter/html.ex

+32-5
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ defmodule ExDoc.Formatter.HTML do
209209
defp generate_extras(extras, config) do
210210
generated_extras =
211211
extras
212+
|> Enum.reject(&is_map_key(&1, :url))
212213
|> with_prev_next()
213214
|> Enum.map(fn {node, prev, next} ->
214215
filename = "#{node.id}.html"
@@ -349,6 +350,7 @@ defmodule ExDoc.Formatter.HTML do
349350

350351
extras =
351352
config.extras
353+
|> Enum.map(&normalize_extras/1)
352354
|> Task.async_stream(
353355
&build_extra(&1, groups, language, autolink_opts, source_url_pattern),
354356
timeout: :infinity
@@ -384,10 +386,31 @@ defmodule ExDoc.Formatter.HTML do
384386
end)
385387
end
386388

389+
defp normalize_extras(base) when is_binary(base), do: {base, %{}}
390+
defp normalize_extras({base, opts}), do: {base, Map.new(opts)}
391+
387392
defp disambiguate_id(extra, discriminator) do
388393
Map.put(extra, :id, "#{extra.id}-#{discriminator}")
389394
end
390395

396+
defp build_extra({input, %{url: _} = input_options}, groups, _lang, _auto, _url_pattern) do
397+
input = to_string(input)
398+
title = input_options[:title] || filename_to_title(input)
399+
group = GroupMatcher.match_extra(groups, input)
400+
401+
# TODO: Can we make the content/source a link?
402+
403+
%{
404+
group: group,
405+
id: Utils.text_to_id(title),
406+
source_path: input_options[:url],
407+
source_url: input_options[:url],
408+
title: title,
409+
title_content: title,
410+
url: input_options[:url]
411+
}
412+
end
413+
391414
defp build_extra({input, input_options}, groups, language, autolink_opts, source_url_pattern) do
392415
input = to_string(input)
393416
id = input_options[:filename] || input |> filename_to_title() |> Utils.text_to_id()
@@ -447,10 +470,6 @@ defmodule ExDoc.Formatter.HTML do
447470
}
448471
end
449472

450-
defp build_extra(input, groups, language, autolink_opts, source_url_pattern) do
451-
build_extra({input, []}, groups, language, autolink_opts, source_url_pattern)
452-
end
453-
454473
defp normalize_search_data!(nil), do: nil
455474

456475
defp normalize_search_data!(search_data) when is_list(search_data) do
@@ -602,7 +621,15 @@ defmodule ExDoc.Formatter.HTML do
602621

603622
{path, opts} ->
604623
base = path |> to_string() |> Path.basename()
605-
{base, opts[:filename] || Utils.text_to_id(Path.rootname(base))}
624+
625+
txid =
626+
cond do
627+
filename = opts[:filename] -> filename
628+
url = opts[:url] -> url
629+
true -> Utils.text_to_id(Path.rootname(base))
630+
end
631+
632+
{base, txid}
606633
end)
607634
end
608635
end

lib/ex_doc/formatter/html/search_data.ex

+30-30
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,8 @@ defmodule ExDoc.Formatter.HTML.SearchData do
1818
["searchData=" | ExDoc.Utils.to_json(data)]
1919
end
2020

21-
defp extra(map) do
22-
if custom_search_data = map[:search_data] do
23-
extra_search_data(map, custom_search_data)
24-
else
25-
{intro, sections} = extract_sections_from_markdown(map.source)
26-
27-
intro_json_item =
28-
encode(
29-
"#{map.id}.html",
30-
map.title,
31-
:extras,
32-
intro
33-
)
34-
35-
section_json_items =
36-
for {header, body} <- sections do
37-
encode(
38-
"#{map.id}.html##{Utils.text_to_id(header)}",
39-
header <> " - #{map.title}",
40-
:extras,
41-
body
42-
)
43-
end
44-
45-
[intro_json_item | section_json_items]
46-
end
47-
end
48-
49-
defp extra_search_data(map, custom_search_data) do
50-
Enum.map(custom_search_data, fn item ->
21+
defp extra(%{search_data: search_data} = map) when is_list(search_data) do
22+
Enum.map(search_data, fn item ->
5123
link =
5224
if item.anchor === "" do
5325
"#{map.id}.html"
@@ -59,6 +31,34 @@ defmodule ExDoc.Formatter.HTML.SearchData do
5931
end)
6032
end
6133

34+
defp extra(%{url: url} = map) do
35+
[encode("#{map.id}", map.title, :extras, url)]
36+
end
37+
38+
defp extra(map) do
39+
{intro, sections} = extract_sections_from_markdown(map.source)
40+
41+
intro_json_item =
42+
encode(
43+
"#{map.id}.html",
44+
map.title,
45+
:extras,
46+
intro
47+
)
48+
49+
section_json_items =
50+
for {header, body} <- sections do
51+
encode(
52+
"#{map.id}.html##{Utils.text_to_id(header)}",
53+
header <> " - #{map.title}",
54+
:extras,
55+
body
56+
)
57+
end
58+
59+
[intro_json_item | section_json_items]
60+
end
61+
6262
defp module(%ExDoc.ModuleNode{} = node) do
6363
{intro, sections} = extract_sections(node.doc_format, node)
6464

lib/ex_doc/formatter/html/templates.ex

+9-10
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,9 @@ defmodule ExDoc.Formatter.HTML.Templates do
8282

8383
defp sidebar_extras(extras) do
8484
for extra <- extras do
85-
%{id: id, title: title, group: group, content: content} = extra
85+
%{id: id, title: title, group: group} = extra
8686

87-
item =
88-
%{
89-
id: to_string(id),
90-
title: to_string(title),
91-
group: to_string(group),
92-
headers: extract_headers(content)
93-
}
87+
item = %{id: to_string(id), title: to_string(title), group: to_string(group)}
9488

9589
case extra do
9690
%{search_data: search_data} when is_list(search_data) ->
@@ -103,10 +97,15 @@ defmodule ExDoc.Formatter.HTML.Templates do
10397
}
10498
end)
10599

106-
Map.put(item, :searchData, search_data)
100+
item
101+
|> Map.put(:headers, extract_headers(extra.content))
102+
|> Map.put(:searchData, search_data)
103+
104+
%{url: url} when is_binary(url) ->
105+
Map.put(item, :url, url)
107106

108107
_ ->
109-
item
108+
Map.put(item, :headers, extract_headers(extra.content))
110109
end
111110
end
112111
end

mix.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
%{
2-
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
2+
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
33
"easyhtml": {:hex, :easyhtml, "0.3.2", "050adfc8074f53b261f7dfe83303d864f1fbf5988245b369f8fdff1bf4c4b3e6", [:mix], [{:floki, "~> 0.35", [hex: :floki, repo: "hexpm", optional: false]}], "hexpm", "b6a936f91612a4870aa3e828cd8da5a08d9e3b6221b4d3012b6ec70b87845d06"},
44
"floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"},
55
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},

test/ex_doc/formatter/html_test.exs

+18
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ defmodule ExDoc.Formatter.HTMLTest do
112112
assert to_string(bar_content["h1"]) == "README bar"
113113
end
114114

115+
test "extras defined as external urls", %{tmp_dir: tmp_dir} = context do
116+
config =
117+
doc_config(context,
118+
extras: [
119+
"README.md",
120+
"Elixir": [url: "https://elixir-lang.org"]
121+
]
122+
)
123+
124+
File.write!("#{tmp_dir}/README.md", "README")
125+
126+
generate_docs(config)
127+
128+
content = File.read!(tmp_dir <> "/html/README.html")
129+
130+
assert content =~ "https://elixir-lang.org"
131+
end
132+
115133
test "warns when generating an index.html file with an invalid redirect",
116134
%{tmp_dir: tmp_dir} = context do
117135
output =

0 commit comments

Comments
 (0)