Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

“Edit this page” → “Edit on GitHub/GitLab/Bitbucket” #1177

Merged
merged 3 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions docs/user_guide/source-buttons.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Source Buttons

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

Add an Edit this Page button
============================
Add an edit button
==================

You can add a button to each page that will allow users to edit the page text
directly and submit a pull request to update the documentation. To include this
Expand Down Expand Up @@ -80,6 +80,37 @@ any other context values.
"some_other_arg": "?some-other-arg"
}
With the predefined providers, the link text reads "Edit on GitHub/GitLab/Bitbucket".
By default, a simple "Edit" is used if you use a custom URL. However, you can set
a provider name like this:

.. code:: python
html_context = {
"edit_page_url_template": "...",
"edit_page_provider_name": "Provider",
}
This will turn the link into "Edit on Provider".


Custom link text
----------------

You can change the default text by extending the ``edit-this-page.html``
template. For example, if you have ``templates_path = ["_templates"]``
in your Sphinx configuration, you could put this code in
`_templates/edit-this-page.html`:

.. code:: html+jinja

{% extends "!components/edit-this-page.html" %}

{% block edit_this_page_text %}
Edit this page
{% endblock %}


View Source link
================

Expand Down
29 changes: 16 additions & 13 deletions src/pydata_sphinx_theme/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,8 +779,8 @@ def extract_level_recursive(ul, navs_list):
def setup_edit_url(app, pagename, templatename, context, doctree):
"""Add a function that jinja can access for returning the edit URL of a page."""

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

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

edit_url_attrs = {}
edit_attrs = {}

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

edit_url_attrs[("edit_page_url_template",)] = url_template

edit_url_attrs.update(
edit_attrs.update(
{
("bitbucket_user", "bitbucket_repo", "bitbucket_version"): (
"Bitbucket",
"{{ bitbucket_url }}/{{ bitbucket_user }}/{{ bitbucket_repo }}"
"/src/{{ bitbucket_version }}"
"/{{ doc_path }}{{ file_name }}?mode=edit"
"/{{ doc_path }}{{ file_name }}?mode=edit",
),
("github_user", "github_repo", "github_version"): (
"GitHub",
"{{ github_url }}/{{ github_user }}/{{ github_repo }}"
"/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}"
"/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}",
),
("gitlab_user", "gitlab_repo", "gitlab_version"): (
"GitLab",
"{{ gitlab_url }}/{{ gitlab_user }}/{{ gitlab_repo }}"
"/-/edit/{{ gitlab_version }}/{{ doc_path }}{{ file_name }}"
"/-/edit/{{ gitlab_version }}/{{ doc_path }}{{ file_name }}",
),
}
)
Expand All @@ -831,17 +834,17 @@ def get_edit_url():
doc_context.update(context)
doc_context.update(doc_path=doc_path, file_name=file_name)

for attrs, url_template in edit_url_attrs.items():
for attrs, (provider, url_template) in edit_attrs.items():
if all(doc_context.get(attr) not in [None, "None"] for attr in attrs):
return jinja2.Template(url_template).render(**doc_context)
return provider, jinja2.Template(url_template).render(**doc_context)

raise ExtensionError(
"Missing required value for `use_edit_page_button`. "
"Ensure one set of the following in your `html_context` "
f"configuration: {sorted(edit_url_attrs.keys())}"
f"configuration: {sorted(edit_attrs.keys())}"
)

context["get_edit_url"] = get_edit_url
context["get_edit_provider_and_url"] = get_edit_provider_and_url

# Ensure that the max TOC level is an integer
context["theme_show_toc_level"] = int(context.get("theme_show_toc_level", 1))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
{% if sourcename is defined and theme_use_edit_page_button==true and page_source_suffix %}
{% set src = sourcename.split('.') %}
<div class="tocsection editthispage">
<a href="{{ get_edit_url() }}">
<i class="fa-solid fa-pencil"></i> {{ _("Edit this page") }}
<a href="{{ get_edit_provider_and_url()[1] }}">
<i class="fa-solid fa-pencil"></i>
{% set provider = get_edit_provider_and_url()[0] %}
{% block edit_this_page_text %}
{% if provider %}
{% trans provider=provider %}Edit on {{ provider }}{% endtrans %}
jeanas marked this conversation as resolved.
Show resolved Hide resolved
{% else %}
{% trans %}Edit{% endtrans %}
{% endif %}
{% endblock %}
</a>
</div>
{% endif %}
61 changes: 43 additions & 18 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ def test_included_toc(sphinx_build_factory):
"github_version": "HEAD",
"doc_path": "docs",
},
"https://github.com/foo/bar/edit/HEAD/docs/index.rst",
("Edit on GitHub", "https://github.com/foo/bar/edit/HEAD/docs/index.rst"),
],
[
{
Expand All @@ -504,7 +504,7 @@ def test_included_toc(sphinx_build_factory):
"gitlab_version": "HEAD",
"doc_path": "docs",
},
"https://gitlab.com/foo/bar/-/edit/HEAD/docs/index.rst",
("Edit on GitLab", "https://gitlab.com/foo/bar/-/edit/HEAD/docs/index.rst"),
],
[
{
Expand All @@ -513,7 +513,10 @@ def test_included_toc(sphinx_build_factory):
"bitbucket_version": "HEAD",
"doc_path": "docs",
},
"https://bitbucket.org/foo/bar/src/HEAD/docs/index.rst?mode=edit",
(
"Edit on Bitbucket",
"https://bitbucket.org/foo/bar/src/HEAD/docs/index.rst?mode=edit",
),
],
]

Expand All @@ -526,10 +529,10 @@ def test_included_toc(sphinx_build_factory):
key: f"{value}/" if key == "doc_path" else value
for key, value in html_context.items()
},
# the URL does not change
url,
# the text and URL do not change
text_and_url,
]
for html_context, url in good_edits
for html_context, text_and_url in good_edits
]

# copy the "good" ones, provide a `<whatever>_url` based off the default
Expand All @@ -541,11 +544,14 @@ def test_included_toc(sphinx_build_factory):
# add a provider url
**{f"{provider}_url": f"https://{provider}.example.com"},
),
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}""",
(
text,
f"""https://{provider}.example.com/foo/{url.split("/foo/")[1]}""",
),
]
for html_context, url in good_edits
for provider in ["gitlab", "bitbucket", "github"]
if provider in url
for html_context, (text, url) in good_edits
for provider in ["github", "gitlab", "bitbucket"]
if provider in text.lower()
]

# missing any of the values should fail
Expand All @@ -560,7 +566,7 @@ def test_included_toc(sphinx_build_factory):
},
None,
]
for html_context, url in good_edits
for html_context, _ in good_edits
]

# a good custom URL template
Expand All @@ -571,7 +577,20 @@ def test_included_toc(sphinx_build_factory):
"https://dvcs.example.com/foo/bar/edit/HEAD/{{ file_name }}"
)
},
"https://dvcs.example.com/foo/bar/edit/HEAD/index.rst",
("Edit", "https://dvcs.example.com/foo/bar/edit/HEAD/index.rst"),
]
]

# a good custom URL template with an additional provider name
good_custom_with_provider = [
[
{
"edit_page_url_template": (
"https://dvcs.example.com/foo/bar/edit/HEAD/{{ file_name }}"
),
"edit_page_provider_name": "FooProvider",
},
("Edit on FooProvider", "https://dvcs.example.com/foo/bar/edit/HEAD/index.rst"),
]
]

Expand All @@ -594,24 +613,31 @@ def test_included_toc(sphinx_build_factory):
]


@pytest.mark.parametrize("html_context,edit_url", all_edits)
def test_edit_page_url(sphinx_build_factory, html_context, edit_url):
@pytest.mark.parametrize("html_context,edit_text_and_url", all_edits)
def test_edit_page_url(sphinx_build_factory, html_context, edit_text_and_url):
confoverrides = {
"html_theme_options.use_edit_page_button": True,
"html_context": html_context,
}
sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides)

if edit_url is None:
with pytest.raises(sphinx.errors.ExtensionError):
if edit_text_and_url is None:
with pytest.raises(
sphinx.errors.ExtensionError, match="Missing required value"
):
sphinx_build.build()
return

edit_text, edit_url = edit_text_and_url
sphinx_build.build()
index_html = sphinx_build.html_tree("index.html")
edit_link = index_html.select(".editthispage a")
assert edit_link, "no edit link found"
assert edit_link[0].attrs["href"] == edit_url, f"edit link didn't match {edit_link}"
# First child is the icon
assert (
list(edit_link[0].strings)[1].strip() == edit_text
), f"edit text didn't match {edit_text}"


@pytest.mark.parametrize(
Expand All @@ -636,7 +662,6 @@ def test_edit_page_url(sphinx_build_factory, html_context, edit_url):
],
)
def test_analytics(sphinx_build_factory, provider, tags):

confoverrides = provider
sphinx_build = sphinx_build_factory("base", confoverrides=confoverrides)
sphinx_build.build()
Expand Down Expand Up @@ -895,7 +920,7 @@ def test_translations(sphinx_build_factory):
# TODO: Add translations where there are english phrases below
sidebar_secondary = index.select(".bd-sidebar-secondary")[0]
assert "Montrer le code source" in str(sidebar_secondary)
assert "Edit this page" in str(sidebar_secondary)
assert "Edit on GitHub" in str(sidebar_secondary)

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