Skip to content

Commit 8d8bcb8

Browse files
authored
“Edit this page” → “Edit on GitHub/GitLab/Bitbucket” (#1177)
* “Edit this page” → “Edit on GitHub/GitLab/Bitbucket” Fixes #1172 * Add tests * Fix typo
1 parent 30b2c52 commit 8d8bcb8

File tree

4 files changed

+102
-35
lines changed

4 files changed

+102
-35
lines changed

docs/user_guide/source-buttons.rst

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ Source Buttons
44

55
Source buttons are links to the source of your page's content (either on your site, or on hosting sites like GitHub).
66

7-
Add an Edit this Page button
8-
============================
7+
Add an edit button
8+
==================
99

1010
You can add a button to each page that will allow users to edit the page text
1111
directly and submit a pull request to update the documentation. To include this
@@ -80,6 +80,37 @@ any other context values.
8080
"some_other_arg": "?some-other-arg"
8181
}
8282
83+
With the predefined providers, the link text reads "Edit on GitHub/GitLab/Bitbucket".
84+
By default, a simple "Edit" is used if you use a custom URL. However, you can set
85+
a provider name like this:
86+
87+
.. code:: python
88+
89+
html_context = {
90+
"edit_page_url_template": "...",
91+
"edit_page_provider_name": "Provider",
92+
}
93+
94+
This will turn the link into "Edit on Provider".
95+
96+
97+
Custom link text
98+
----------------
99+
100+
You can change the default text by extending the ``edit-this-page.html``
101+
template. For example, if you have ``templates_path = ["_templates"]``
102+
in your Sphinx configuration, you could put this code in
103+
`_templates/edit-this-page.html`:
104+
105+
.. code:: html+jinja
106+
107+
{% extends "!components/edit-this-page.html" %}
108+
109+
{% block edit_this_page_text %}
110+
Edit this page
111+
{% endblock %}
112+
113+
83114
View Source link
84115
================
85116

src/pydata_sphinx_theme/__init__.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -779,8 +779,8 @@ def extract_level_recursive(ul, navs_list):
779779
def setup_edit_url(app, pagename, templatename, context, doctree):
780780
"""Add a function that jinja can access for returning the edit URL of a page."""
781781

782-
def get_edit_url():
783-
"""Return a URL for an "edit this page" link."""
782+
def get_edit_provider_and_url():
783+
"""Return a provider name and a URL for an "edit this page" link."""
784784
file_name = f"{pagename}{context['page_source_suffix']}"
785785

786786
# Make sure that doc_path has a path separator only if it exists (to avoid //)
@@ -794,7 +794,7 @@ def get_edit_url():
794794
"gitlab_url": "https://gitlab.com",
795795
}
796796

797-
edit_url_attrs = {}
797+
edit_attrs = {}
798798

799799
# ensure custom URL is checked first, if given
800800
url_template = context.get("edit_page_url_template")
@@ -806,23 +806,26 @@ def get_edit_url():
806806
"Ensure `file_name` appears in `edit_page_url_template`: "
807807
f"{url_template}"
808808
)
809+
provider_name = context.get("edit_page_provider_name")
810+
edit_attrs[("edit_page_url_template",)] = (provider_name, url_template)
809811

810-
edit_url_attrs[("edit_page_url_template",)] = url_template
811-
812-
edit_url_attrs.update(
812+
edit_attrs.update(
813813
{
814814
("bitbucket_user", "bitbucket_repo", "bitbucket_version"): (
815+
"Bitbucket",
815816
"{{ bitbucket_url }}/{{ bitbucket_user }}/{{ bitbucket_repo }}"
816817
"/src/{{ bitbucket_version }}"
817-
"/{{ doc_path }}{{ file_name }}?mode=edit"
818+
"/{{ doc_path }}{{ file_name }}?mode=edit",
818819
),
819820
("github_user", "github_repo", "github_version"): (
821+
"GitHub",
820822
"{{ github_url }}/{{ github_user }}/{{ github_repo }}"
821-
"/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}"
823+
"/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}",
822824
),
823825
("gitlab_user", "gitlab_repo", "gitlab_version"): (
826+
"GitLab",
824827
"{{ gitlab_url }}/{{ gitlab_user }}/{{ gitlab_repo }}"
825-
"/-/edit/{{ gitlab_version }}/{{ doc_path }}{{ file_name }}"
828+
"/-/edit/{{ gitlab_version }}/{{ doc_path }}{{ file_name }}",
826829
),
827830
}
828831
)
@@ -831,17 +834,17 @@ def get_edit_url():
831834
doc_context.update(context)
832835
doc_context.update(doc_path=doc_path, file_name=file_name)
833836

834-
for attrs, url_template in edit_url_attrs.items():
837+
for attrs, (provider, url_template) in edit_attrs.items():
835838
if all(doc_context.get(attr) not in [None, "None"] for attr in attrs):
836-
return jinja2.Template(url_template).render(**doc_context)
839+
return provider, jinja2.Template(url_template).render(**doc_context)
837840

838841
raise ExtensionError(
839842
"Missing required value for `use_edit_page_button`. "
840843
"Ensure one set of the following in your `html_context` "
841-
f"configuration: {sorted(edit_url_attrs.keys())}"
844+
f"configuration: {sorted(edit_attrs.keys())}"
842845
)
843846

844-
context["get_edit_url"] = get_edit_url
847+
context["get_edit_provider_and_url"] = get_edit_provider_and_url
845848

846849
# Ensure that the max TOC level is an integer
847850
context["theme_show_toc_level"] = int(context.get("theme_show_toc_level", 1))
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
{% if sourcename is defined and theme_use_edit_page_button==true and page_source_suffix %}
22
{% set src = sourcename.split('.') %}
33
<div class="tocsection editthispage">
4-
<a href="{{ get_edit_url() }}">
5-
<i class="fa-solid fa-pencil"></i> {{ _("Edit this page") }}
4+
<a href="{{ get_edit_provider_and_url()[1] }}">
5+
<i class="fa-solid fa-pencil"></i>
6+
{% set provider = get_edit_provider_and_url()[0] %}
7+
{% block edit_this_page_text %}
8+
{% if provider %}
9+
{% trans provider=provider %}Edit on {{ provider }}{% endtrans %}
10+
{% else %}
11+
{% trans %}Edit{% endtrans %}
12+
{% endif %}
13+
{% endblock %}
614
</a>
715
</div>
816
{% endif %}

tests/test_build.py

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ def test_included_toc(sphinx_build_factory):
495495
"github_version": "HEAD",
496496
"doc_path": "docs",
497497
},
498-
"https://github.com/foo/bar/edit/HEAD/docs/index.rst",
498+
("Edit on GitHub", "https://github.com/foo/bar/edit/HEAD/docs/index.rst"),
499499
],
500500
[
501501
{
@@ -504,7 +504,7 @@ def test_included_toc(sphinx_build_factory):
504504
"gitlab_version": "HEAD",
505505
"doc_path": "docs",
506506
},
507-
"https://gitlab.com/foo/bar/-/edit/HEAD/docs/index.rst",
507+
("Edit on GitLab", "https://gitlab.com/foo/bar/-/edit/HEAD/docs/index.rst"),
508508
],
509509
[
510510
{
@@ -513,7 +513,10 @@ def test_included_toc(sphinx_build_factory):
513513
"bitbucket_version": "HEAD",
514514
"doc_path": "docs",
515515
},
516-
"https://bitbucket.org/foo/bar/src/HEAD/docs/index.rst?mode=edit",
516+
(
517+
"Edit on Bitbucket",
518+
"https://bitbucket.org/foo/bar/src/HEAD/docs/index.rst?mode=edit",
519+
),
517520
],
518521
]
519522

@@ -526,10 +529,10 @@ def test_included_toc(sphinx_build_factory):
526529
key: f"{value}/" if key == "doc_path" else value
527530
for key, value in html_context.items()
528531
},
529-
# the URL does not change
530-
url,
532+
# the text and URL do not change
533+
text_and_url,
531534
]
532-
for html_context, url in good_edits
535+
for html_context, text_and_url in good_edits
533536
]
534537

535538
# copy the "good" ones, provide a `<whatever>_url` based off the default
@@ -541,11 +544,14 @@ def test_included_toc(sphinx_build_factory):
541544
# add a provider url
542545
**{f"{provider}_url": f"https://{provider}.example.com"},
543546
),
544-
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}""",
547+
(
548+
text,
549+
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}""",
550+
),
545551
]
546-
for html_context, url in good_edits
547-
for provider in ["gitlab", "bitbucket", "github"]
548-
if provider in url
552+
for html_context, (text, url) in good_edits
553+
for provider in ["github", "gitlab", "bitbucket"]
554+
if provider in text.lower()
549555
]
550556

551557
# missing any of the values should fail
@@ -560,7 +566,7 @@ def test_included_toc(sphinx_build_factory):
560566
},
561567
None,
562568
]
563-
for html_context, url in good_edits
569+
for html_context, _ in good_edits
564570
]
565571

566572
# a good custom URL template
@@ -571,7 +577,20 @@ def test_included_toc(sphinx_build_factory):
571577
"https://dvcs.example.com/foo/bar/edit/HEAD/{{ file_name }}"
572578
)
573579
},
574-
"https://dvcs.example.com/foo/bar/edit/HEAD/index.rst",
580+
("Edit", "https://dvcs.example.com/foo/bar/edit/HEAD/index.rst"),
581+
]
582+
]
583+
584+
# a good custom URL template with an additional provider name
585+
good_custom_with_provider = [
586+
[
587+
{
588+
"edit_page_url_template": (
589+
"https://dvcs.example.com/foo/bar/edit/HEAD/{{ file_name }}"
590+
),
591+
"edit_page_provider_name": "FooProvider",
592+
},
593+
("Edit on FooProvider", "https://dvcs.example.com/foo/bar/edit/HEAD/index.rst"),
575594
]
576595
]
577596

@@ -594,24 +613,31 @@ def test_included_toc(sphinx_build_factory):
594613
]
595614

596615

597-
@pytest.mark.parametrize("html_context,edit_url", all_edits)
598-
def test_edit_page_url(sphinx_build_factory, html_context, edit_url):
616+
@pytest.mark.parametrize("html_context,edit_text_and_url", all_edits)
617+
def test_edit_page_url(sphinx_build_factory, html_context, edit_text_and_url):
599618
confoverrides = {
600619
"html_theme_options.use_edit_page_button": True,
601620
"html_context": html_context,
602621
}
603622
sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides)
604623

605-
if edit_url is None:
606-
with pytest.raises(sphinx.errors.ExtensionError):
624+
if edit_text_and_url is None:
625+
with pytest.raises(
626+
sphinx.errors.ExtensionError, match="Missing required value"
627+
):
607628
sphinx_build.build()
608629
return
609630

631+
edit_text, edit_url = edit_text_and_url
610632
sphinx_build.build()
611633
index_html = sphinx_build.html_tree("index.html")
612634
edit_link = index_html.select(".editthispage a")
613635
assert edit_link, "no edit link found"
614636
assert edit_link[0].attrs["href"] == edit_url, f"edit link didn't match {edit_link}"
637+
# First child is the icon
638+
assert (
639+
list(edit_link[0].strings)[1].strip() == edit_text
640+
), f"edit text didn't match {edit_text}"
615641

616642

617643
@pytest.mark.parametrize(
@@ -636,7 +662,6 @@ def test_edit_page_url(sphinx_build_factory, html_context, edit_url):
636662
],
637663
)
638664
def test_analytics(sphinx_build_factory, provider, tags):
639-
640665
confoverrides = provider
641666
sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides)
642667
sphinx_build.build()
@@ -895,7 +920,7 @@ def test_translations(sphinx_build_factory):
895920
# TODO: Add translations where there are english phrases below
896921
sidebar_secondary = index.select(".bd-sidebar-secondary")[0]
897922
assert "Montrer le code source" in str(sidebar_secondary)
898-
assert "Edit this page" in str(sidebar_secondary)
923+
assert "Edit on GitHub" in str(sidebar_secondary)
899924

900925
# TODO: Add translations where there are english phrases below
901926
header = index.select(".bd-header")[0]

0 commit comments

Comments
 (0)