Skip to content

Commit 15f3a59

Browse files
authored
Allow listing outside URLs in extras (#2103)
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 26129ef commit 15f3a59

File tree

16 files changed

+195
-82
lines changed

16 files changed

+195
-82
lines changed

assets/css/icons.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
--icon-add: "\ea13";
2525
--icon-subtract: "\f1af";
2626
--icon-error-warning: "\eca1";
27+
--icon-external-link-line: "\ecaf";
2728
--icon-information: "\ee59";
2829
--icon-alert: "\ea21";
2930
--icon-double-quotes-l: "\ec51";
@@ -44,6 +45,7 @@
4445
.ri-arrow-up-s-line:before { content: var(--icon-arrow-up-s); }
4546
.ri-arrow-down-s-line:before { content: var(--icon-arrow-down-s); }
4647
.ri-arrow-right-s-line:before { content: var(--icon-arrow-right-s); }
48+
.ri-external-link-line:before { content: var(--icon-external-link-line); }
4749
.ri-search-2-line:before { content: var(--icon-search-2-line); }
4850
.ri-menu-line:before { content: var(--icon-menu-line); }
4951
.ri-close-line:before { content: var(--icon-close-line); }

assets/css/sidebar.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
color: var(--sidebarHover);
3838
}
3939

40+
.sidebar .external-link {
41+
margin: 0 2.5px 0 0;
42+
}
43+
4044
.sidebar .sidebar-header {
4145
background-color: var(--sidebarHeader);
4246
width: 100%;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
settings-3-line,add-line,subtract-line,arrow-up-s-line,arrow-down-s-line,arrow-right-s-line,search-2-line,menu-line,close-line,link-m,code-s-slash-line,error-warning-line,information-line,alert-line,double-quotes-l,printer-line
1+
add-line,alert-line,arrow-down-s-line,arrow-right-s-line,arrow-up-s-line,close-line,code-s-slash-line,double-quotes-l,error-warning-line,external-link-line,information-line,link-m,menu-line,printer-line,search-2-line,settings-3-line,subtract-line

assets/fonts/remixicon.woff2

140 Bytes
Binary file not shown.

assets/js/sidebar/sidebar-list.js

Lines changed: 5 additions & 1 deletion
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,10 @@ 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, translate}, [
83+
node.nested_title || node.title,
84+
node.url ? el('i', {class: 'external-link ri-external-link-line'}) : null
85+
].filter(Boolean)),
8286
...childList(`node-${node.id}-headers`,
8387
hasHeaders
8488
? renderHeaders(node)

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

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ex_doc/formatter/epub.ex

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,19 @@ defmodule ExDoc.Formatter.EPUB do
6161
end
6262

6363
defp generate_extras(config) do
64-
for {_title, extras} <- config.extras do
65-
Enum.each(extras, fn %{id: id, title: title, title_content: title_content, content: content} ->
66-
output = "#{config.output}/OEBPS/#{id}.xhtml"
67-
html = Templates.extra_template(config, title, title_content, content)
64+
for {_title, extras} <- config.extras,
65+
extra_config <- extras,
66+
not is_map_key(extra_config, :url) do
67+
%{id: id, title: title, title_content: title_content, content: content} = extra_config
6868

69-
if File.regular?(output) do
70-
Utils.warn("file #{Path.relative_to_cwd(output)} already exists", [])
71-
end
69+
output = "#{config.output}/OEBPS/#{id}.xhtml"
70+
html = Templates.extra_template(config, title, title_content, content)
7271

73-
File.write!(output, html)
74-
end)
72+
if File.regular?(output) do
73+
Utils.warn("file #{Path.relative_to_cwd(output)} already exists", [])
74+
end
75+
76+
File.write!(output, html)
7577
end
7678
end
7779

lib/ex_doc/formatter/html.ex

Lines changed: 28 additions & 10 deletions
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,21 @@ 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] || input
399+
group = GroupMatcher.match_extra(groups, input_options[:url])
400+
401+
%{group: group, id: Utils.text_to_id(title), title: title, url: input_options[:url]}
402+
end
403+
391404
defp build_extra({input, input_options}, groups, language, autolink_opts, source_url_pattern) do
392405
input = to_string(input)
393406
id = input_options[:filename] || input |> filename_to_title() |> Utils.text_to_id()
@@ -447,10 +460,6 @@ defmodule ExDoc.Formatter.HTML do
447460
}
448461
end
449462

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-
454463
defp normalize_search_data!(nil), do: nil
455464

456465
defp normalize_search_data!(search_data) when is_list(search_data) do
@@ -595,14 +604,23 @@ defmodule ExDoc.Formatter.HTML do
595604
end
596605

597606
defp extra_paths(config) do
598-
Map.new(config.extras, fn
599-
path when is_binary(path) ->
607+
Enum.reduce(config.extras, %{}, fn
608+
path, acc when is_binary(path) ->
600609
base = Path.basename(path)
601-
{base, Utils.text_to_id(Path.rootname(base))}
602610

603-
{path, opts} ->
604-
base = path |> to_string() |> Path.basename()
605-
{base, opts[:filename] || Utils.text_to_id(Path.rootname(base))}
611+
Map.put(acc, base, Utils.text_to_id(Path.rootname(base)))
612+
613+
{path, opts}, acc ->
614+
if Keyword.has_key?(opts, :url) do
615+
acc
616+
else
617+
base = path |> to_string() |> Path.basename()
618+
619+
name =
620+
Keyword.get_lazy(opts, :filename, fn -> Utils.text_to_id(Path.rootname(base)) end)
621+
622+
Map.put(acc, base, name)
623+
end
606624
end)
607625
end
608626
end

lib/ex_doc/formatter/html/search_data.ex

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,10 @@ 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
21+
defp extra(%{url: _}), do: []
4822

49-
defp extra_search_data(map, custom_search_data) do
50-
Enum.map(custom_search_data, fn item ->
23+
defp extra(%{search_data: search_data} = map) when is_list(search_data) do
24+
Enum.map(search_data, fn item ->
5125
link =
5226
if item.anchor === "" do
5327
"#{map.id}.html"
@@ -59,6 +33,30 @@ defmodule ExDoc.Formatter.HTML.SearchData do
5933
end)
6034
end
6135

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

lib/ex_doc/formatter/html/templates.ex

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,9 @@ defmodule ExDoc.Formatter.HTML.Templates do
5858

5959
defp sidebar_extras(extras) do
6060
for extra <- extras do
61-
%{id: id, title: title, group: group, content: content} = extra
61+
%{id: id, title: title, group: group} = extra
6262

63-
item =
64-
%{
65-
id: to_string(id),
66-
title: to_string(title),
67-
group: to_string(group),
68-
headers: extract_headers(content)
69-
}
63+
item = %{id: to_string(id), title: to_string(title), group: to_string(group)}
7064

7165
case extra do
7266
%{search_data: search_data} when is_list(search_data) ->
@@ -79,10 +73,15 @@ defmodule ExDoc.Formatter.HTML.Templates do
7973
}
8074
end)
8175

82-
Map.put(item, :searchData, search_data)
76+
item
77+
|> Map.put(:headers, extract_headers(extra.content))
78+
|> Map.put(:searchData, search_data)
79+
80+
%{url: url} when is_binary(url) ->
81+
Map.put(item, :url, url)
8382

8483
_ ->
85-
item
84+
Map.put(item, :headers, extract_headers(extra.content))
8685
end
8786
end
8887
end

0 commit comments

Comments
 (0)