Skip to content

Commit b4940e4

Browse files
committed
EmbedAPI: clean images (src) properly from inside a tooltip
When returning the content to be injected in a tooltip, besides cleaning the `a.href` we are also cleaning the `img.src` to make them absolute and render the images properly. See readthedocs/sphinx-hoverxref#200
1 parent 3d078c7 commit b4940e4

File tree

2 files changed

+42
-16
lines changed

2 files changed

+42
-16
lines changed

readthedocs/embed/tests/test_links.py

+24
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,23 @@
9090
),
9191
]
9292

93+
imagedata = [
94+
URLData(
95+
html_base_url,
96+
"/_images/image.png",
97+
"/_images/image.png",
98+
),
99+
URLData(
100+
html_base_url,
101+
"relative/section/image.png",
102+
"https://t.readthedocs.io/en/latest/relative/section/image.png",
103+
),
104+
URLData(
105+
"https://t.readthedocs.io/en/latest/internal/deep/page/topic.html",
106+
"../../../_images/image.png",
107+
"https://t.readthedocs.io/en/latest/internal/deep/page/../../../_images/image.png",
108+
),
109+
]
93110

94111
@pytest.mark.parametrize('url', htmldata + dirhtmldata)
95112
def test_clean_links(url):
@@ -98,6 +115,13 @@ def test_clean_links(url):
98115
assert response.find('a').attr['href'] == url.expected
99116

100117

118+
@pytest.mark.parametrize("url", imagedata)
119+
def test_clean_images(url):
120+
pq = PyQuery(f'<body><img alt="image alt content" src="{url.ref}"></img></body>')
121+
response = clean_references(pq, url.docurl)
122+
assert response.find("img").attr["src"] == url.expected
123+
124+
101125
def test_two_links():
102126
"""
103127
First link does not affect the second one.

readthedocs/embed/utils.py

+18-16
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ def recurse_while_none(element):
1818

1919
def clean_references(obj, url, html_raw_response=False):
2020
"""
21-
Rewrite (internal) links to make them absolute.
21+
Rewrite (internal) links (href) and images (src) to make them absolute.
2222
23-
1. external links are not changed
23+
1. external links/images are not changed
2424
2. prepend URL to links that are just fragments (e.g. #section)
25-
3. prepend URL (without filename) to internal relative links
25+
3. prepend URL (without filename) to internal relative links/images
2626
"""
2727

2828
# TODO: do not depend on PyQuery
@@ -31,23 +31,25 @@ def clean_references(obj, url, html_raw_response=False):
3131
if url is None:
3232
return obj
3333

34-
for link in obj.find('a'):
34+
for tag in obj.find("a") + obj.find("img"):
3535
base_url = urlparse(url)
36-
# We need to make all internal links, to be absolute
37-
href = link.attrib['href']
38-
parsed_href = urlparse(href)
36+
attribute = "href" if tag.tag == "a" else "src"
37+
value = tag.attrib[attribute]
38+
39+
# We need to make all internal links/images, to be absolute
40+
parsed_href = urlparse(value)
3941
if parsed_href.scheme or parsed_href.path.startswith('/'):
40-
# don't change external links
42+
# don't change external links/images
4143
continue
4244

43-
if not parsed_href.path and parsed_href.fragment:
44-
# href="#section-link"
45-
new_href = base_url.geturl() + href
46-
link.attrib['href'] = new_href
45+
if tag.tag == "a" and not parsed_href.path and parsed_href.fragment:
46+
# It's a link pointing to a specific section inside the target ``href="#section-link"``
47+
cleaned_value = base_url.geturl() + value
48+
tag.attrib[attribute] = cleaned_value
4749
continue
4850

4951
if not base_url.path.endswith('/'):
50-
# internal relative link
52+
# internal relative link/image
5153
# href="../../another.html" and ``base_url`` is not HTMLDir
5254
# (e.g. /en/latest/deep/internal/section/page.html)
5355
# we want to remove the trailing filename (page.html) and use the rest as base URL
@@ -56,11 +58,11 @@ def clean_references(obj, url, html_raw_response=False):
5658

5759
# remove the filename (page.html) from the original document URL (base_url) and,
5860
path, _ = base_url.path.rsplit('/', 1)
59-
# append the value of href (../../another.html) to the base URL.
61+
# append the value of href/src (../../another.html) to the base URL.
6062
base_url = base_url._replace(path=path + '/')
6163

62-
new_href = base_url.geturl() + href
63-
link.attrib['href'] = new_href
64+
cleaned_value = base_url.geturl() + value
65+
tag.attrib[attribute] = cleaned_value
6466

6567
if html_raw_response:
6668
return obj.outerHtml()

0 commit comments

Comments
 (0)