Repository navigation
Force external links to open in a new tab - #920
Conversation
… external links so they open in a new tab.
| document.addEventListener("DOMContentLoaded", function () { | ||
| document.querySelectorAll('a.external').forEach(link => { | ||
| link.setAttribute('target', '_blank'); | ||
| link.setAttribute('rel', 'noopener noreferrer'); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
There are two places we can insert this script, either here in the theme layout doc or in a custom JS doc. The advantage of putting it here is that this file already exists as part of the RTD theme. The downside being it would potentially need re-implementing if the theme was changed.
Moving this to a custom JS file is as simple as adding a new file to src/_static/js with that function, then add:
html_js_files = [
'name_of_new_file.js',
]
To src/conf.py
|
This is working here |
|
The other method I found to achieve the same was this extension, which worked but relies on it being maintained. The only additional benefit from the extension is that it can display an icon next to external links. We could replicate that if we wanted. |
|
If we want per link control, we could use something like this: A Cylc workflow is defined by a flow.cylc configuration file, which uses a nested |location_link|.
.. |location_link| raw:: html
<a href="https://en.wikipedia.org/wiki/INI_file" target="_blank">INI format</a>But that's messy and would be a pain to implement for every link we want to effect. |
|
LGTM. Adding the icon might be simple with a drop of CSS. E.g, This will cause a red "x" symbol to be added after each external link: a.external:after {
content: ' x';
color:red;
}I think the RTD theme imports "Font Awesome" which probably has an appropriate icon, so might be simple. |
@oliver-sanders I can do that. Do you think the JS should be in the theme layout.html file or should I move it to _static/js like the CSS? |
I'm not actually sure how the |
@oliver-sanders I believe I can add: to the conf.py to pick up scripts. That seems like the proper way to do it and it opens the door for any further JS we might want to add, it's just whether it's worth creating a new file in this case. |
|
Sounds good. New files cost little. |
Added some CSS to show an icon next to external links.
|
|
||
| /* Add an icon to external links */ | ||
| a.external::after { | ||
| content: "🔗 ↗ ⧉"; |
There was a problem hiding this comment.
I've looked into using font awesome icons but it looks like on the latest versions of the RTD theme for sphinx, it only bundles specific bits of RTD, so I have been unable to get any icons from them working. I would have liked: this
So assuming FA icons are not possible, which of those three do you like @oliver-sanders? I will adjust the colour, size and position once we pick one.
There was a problem hiding this comment.
Fair 'nough.
Would probs go with ↗
We can mess with the font-size and vertical-align to make it display nicely.
| /* | ||
| Adds target=_blank to external links so they open in a new tab: | ||
| - noopener: prevents the new page accessing window.opener (tabnabbing protection) | ||
| - noreferrer: removes referrer info and adds extra safety | ||
| */ | ||
| document.addEventListener("DOMContentLoaded", function () { | ||
| document.querySelectorAll('a.external').forEach(link => { | ||
| link.setAttribute('target', '_blank'); | ||
| link.setAttribute('rel', 'noopener noreferrer'); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Not sure on preferred code/comment style for JS yet, hopefully this is ok?
There was a problem hiding this comment.
Fine by me.
We generally use eslint "standard" for JS.
| # -- Static file locations ----------------------------------------------- | ||
| html_static_path = ['_static'] | ||
|
|
||
| # These paths are either relative to html_static_path | ||
| # or fully qualified paths (eg. https://...) | ||
| # NOTE: these are added to the end of the default/theme static files, so | ||
| # will override them if there are any conflicts. | ||
|
|
||
| # Custom CSS | ||
| html_css_files = [ | ||
| 'css/custom.css', | ||
| ] | ||
|
|
||
| # Custom JS | ||
| html_js_files = [ | ||
| 'js/extern_links_new_tab.js', | ||
| ] |
There was a problem hiding this comment.
Moved the static file settings to their own block.
ok interesting, I'll have a look into why they are tagged differently. I think there is some config that controls what counts as external. I'm thinking about adding some hover text that tells the user a link is going to take them to an external page too. |
@oliver-sanders Which is syntax I am not yet familiar with but appears to either generate or import a module from elsewhere. The links within this module are external when built / viewed on my test server as they link back to the live version of the site. URL of the test site: URL that is linked to: So I would guess this will fix itself on a live build. How we test that I am unsure. |
|
|
In this case, it's reading from Don't worry about this one, I'll poke at it from the cylc-flow end... |
No clean way to handle this one, will just have to ignore it. |
…d with an icon appended. Added hover text (title) to external links saying they are external and open in a new tab. Added an aria label for screen readers to pick up.
| document.querySelectorAll('a.external').forEach(link => { | ||
| link.setAttribute('target', '_blank'); | ||
| link.setAttribute('rel', 'noopener noreferrer'); | ||
| link.setAttribute('title', 'This link will open in a new tab and take you to an external site.'); |
There was a problem hiding this comment.
adds on hover text.
| link.setAttribute('target', '_blank'); | ||
| link.setAttribute('rel', 'noopener noreferrer'); | ||
| link.setAttribute('title', 'This link will open in a new tab and take you to an external site.'); | ||
| link.setAttribute('aria-label', 'External link: opens in a new tab'); |
There was a problem hiding this comment.
additional information for a screen reader.
RyanBcoding
left a comment
There was a problem hiding this comment.
Tested changes. Seems to be working as expected. Comments explain decision for why the changes were made, so happy to approve.





Closes #908 if agreed.
Added some JavaScript to the theme layout which Adds target=_blank to external links so they open in a new tab.
I have seen some discourse online as to whether developers should try to effect the users choice when clicking links (they can already chose to open links in a new tab themselves), however in our case, external links are almost always definitions or further reading type of stuff so it feels a bit jarring for them to take you away from the docs.
Also added an icon and hover text to external links making them obvious.
Built example:

https://wwwspice/~samuel.denton/cylc-doc/8.6.x_Ext_links_new_tab/html/tutorial/scheduling/graphing.html
Requirements check-list
CONTRIBUTING.mdand added my name as a Code Contributor.