jupyter-book
jupyter-book copied to clipboard
Open external URLs in new tab
Hi, Is there a configuration flag, which opens all links going to external sites in a new tab? Thanks a lot in advance!
hi @markusritschel I don't think is is an option for jupyter-book
.
It may not be too hard to support as a feature request: https://stackoverflow.com/questions/25583581/add-open-in-new-tab-links-in-sphinx-restructuredtext
just as part of this discussion - we've had some feedback on our projects that some users don't like this as default behaviour with a preference to open links in a new tab themselves. But I guess the argument for external
only links is that you can't tell the difference between internal
and external
links in many cases.
Hi @mmcky. Thanks for the answer! Maybe another option to make them recognizable would be adding a tiny in-line icon to all links starting with a http/https during the compiling process.?
thanks @markusritschel -- that's a nice idea too. I think a user specified option to enable new tab for external links should be achievable. Thanks for the feedback and ideas. @AakashGfude this might be something we can implement in myst_nb
and add a conf
variable mystnb_externallink_tabs = False/True [Default: False]
I feel like this should be its own separate sphinx extension, since you'd need to over-write Sphinx's own "link writing" nodes to adopt this behavior, I suspect
Can we hijack the output of the HTML renderer? or alter the a
tag in HTML in sphinx-book-theme
. As the solution is just to add target=__blank
attribute in a
tag.
And also all external links, should probably be opened in a new tab as a default? Else it takes the user away from the website. It is considered good practice in the web dev world, as the websites don't want users to leave their site.
If we knew the basename
of the site (e.g. https://mysite.org/book
) then we could always do a "dumb" check for whether a link's target started with this, and if not, add the target=__blank
bit to it. Seems like we could do this with like 5 lines of JS code 🤷♂️ (or, do it on the Sphinx side before the HTML is written)
@choldgraf I guess we can also do this with beautifulSoup, when we are updating other attributes in sphinx-book-theme
or JS one also looks good to me. Want me to give this a try?
hey @choldgraf and @AakashGfude can't we just test for http
or https
and apply to those links. From memory sphinx
uses the following html
structure for internal links
<a class="reference internal" href="amss.html#equation-ts-gov-wo4">(39.8)</a>
@mmcky true. or we can also check for an external
class. For external links, similarly, sphinx has
<a class="reference external"
@AakashGfude ok great.
The link above provides a really simple approach to updating the translator
from sphinx.writers.html import HTMLTranslator
class PatchedHTMLTranslator(HTMLTranslator):
def visit_reference(self, node):
if node.get('newtab') or not (node.get('target') or node.get('internal')
or 'refuri' not in node):
node['target'] = '_blank'
super().visit_reference(node)
def setup(app):
app.set_translator('html', PatchedHTMLTranslator)
@mmcky looks neat. so we are going with making this a part of jupyter-book
. Or will it be a part of the theme?
I see this as a myst_nb
addition or super simple extension. I view jupyter-book
as a cli
/interface
to the executable books software stack.
ooh sorry, myst_nb
vs theme then. I am happy with it being permanent for all software using myst_nb
as external links opening in a new tab is a good default approach.
as external links opening in a new tab is a good default approach.
I think this is up for debate :-). I think it should be an option (but I don't mind if it is on by default).
ooh ok, so you are saying, we should activate this translator function based on mystnb_externallink_tabs = False/True
?
app.set_translator('html', PatchedHTMLTranslator)
looking at the code at first, it seemed like you wanted to make it default. but all clear now.
👍 but let's call it MySTNBHTMLTranslator
and other things can be added (as needed in the future)
Hmm, don't custom translators break things when we build on read the docs? Also wouldn't this then also not work with any other theme or extension that defined a custom translator? (I think this is also why RTD breaks too, since they use a ReadTheDocs HTML Translator, I seem to remember that)
hey @choldgraf not sure I follow fully. This should update the in-built HTMLTranslator
to add a bit of logic around adding the _black
for external links. The builder
shouldn't change (i.e. html
would still be the builder). rtd
will use jupyter-book
to compile the projects?
this is a good question though -- will rtd
use jupyter-book
or myst-nb
to build. It will need to use jupyter-book
to make use of _config.yml
etc. right?
@choldgraf I think I see what you're saying here. Doesn't it depend on the order in which the app get's initialised.
For example if
app.set_translator('html', MySTNBHTMLTranslator)
get's added before any extensions get loaded by sphinx then updated visit/departs should apply to the MySTNBHTMLTranslator. But perhaps a safer way to go is to setup a little extension?
yeah - I think this issue described some of the challenges:
https://github.com/readthedocs/readthedocs.org/issues/6690
but maybe translators can stack somehow?
thanks @choldgraf that thread is really informative.
~~Maybe the best (but not shortest) strategy on this is to add it as a feature upstream in sphinx
?~~
After doing a bit of research it looks like they have had this conversation and elected not to support opening in new tabs
https://groups.google.com/g/sphinx-users/c/NnZVh2X79co?pli=1 with the following opinion:
Hi,
links with an explicit "new window" target are deprecated in HTML; it
should be the choice of the user where to open the link.
cheers,
Georg
They have done it for the htmlhelp builder -- which we could draw some ideas on.
@choldgraf what do you think about the suggestion by @markusritschel to have a small in-line hover icon to could appear when a mouse hovers over the link for opening in a "new-tab"?
Hmmm - one thing we could do is add use an :after
rule and add this little icon: https://fontawesome.com/icons/external-link-alt ? Maybe if it is small enough it wouldn't be too invasive?
Does anyone know of other common patterns that sites use to style external links differently?
I wonder if this is something that @rowanc1 has considered for iooxa?
Hi @choldgraf,
I think this is a good idea. And it could be implemented with a simple css rule in the theme's css, for example.?
If all external links have the class reference external
as @AakashGfude said, something like
a.reference.external:after { /* setting image here */ }
would already do the work. Or, more general (ignoring the own domain, anchors and internal links):
a:not([href*='myjupyterbookdoma.in']):not([href^='#']):not([href^='/']):after { /* setting image here */ }
Another option is using javascript, of course, like they show here: https://css-tricks.com/snippets/jquery/target-only-external-links/. (One could also use favicons of the external web site as pointed out here. But this is then not uniform anymore.)
And in the end, this then linked to a flag in the configuration like mystnb_externallink_tabs = False/True
as suggested by @mmcky would be really convenient. But I haven't made myself familiar enough with Sphinx to know how easy this is to (de)activate a css rule.?
Yeah - as one example, the following rule:
a.reference.external:after {
content: "\f35d";
font-family: 'Font Awesome 5 Free';
font-size: .7em;
vertical-align: text-top;
margin-left: .1em;
color: grey;
}
yields:
Hi @choldgraf , Thanks for providing the CSS rule above. Could you please tell how to properly import Font Awesome to that your customization works? I tried adding:
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/fontawesome.min.css');
in a _static/customizations.css
file which contains also the code below:
a.reference.external:after {
content: "\f35d";
font-family: 'Font Awesome 6 Free';
font-size: .7em;
vertical-align: text-top;
margin-left: .1em;
color: grey;
}
but this did not work. I still get an empty rectangle instead of the Font Awesome icon.
Thanks!
couldn't get font-family: 'Font Awesome ...'
to work, but plain unicode content: "\2b77"
seems to be fine.