Repository: sphinx-gallery/sphinx-gallery

Issue:
Binder icon is hardcoded, which causes a loading failure with on some browsers
See https://github.com/scikit-image/scikit-image/issues/4748

It would be helpful if this line could be changed: https://github.com/sphinx-gallery/sphinx-gallery/blob/master/sphinx_gallery/binder.py#L109
Because the icon is hosted on a third-party website, browsers with "prevent cross-site tracking" preferences remove the icon.

Thank you!

Discussion:

Patch:
diff --git a/README.rst b/README.rst
index 8394e84..1e11097 100644
--- a/README.rst
+++ b/README.rst
@@ -88,3 +88,9 @@ you can do:
     $ pip install -e .
 
 .. installation-end-content
+
+Citation
+========
+
+If you would like to cite Sphinx-Gallery you can do so using our `Zenodo
+deposit <https://zenodo.org/record/3838216>`_.
diff --git a/doc/index.rst b/doc/index.rst
index baf8c6e..72722b1 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -41,6 +41,11 @@ Features of Sphinx-Gallery
    :start-after: installation-begin-content
    :end-before: installation-end-content
 
+Citation
+--------
+
+If you would like to cite Sphinx-Gallery you can do so using our `Zenodo
+deposit <https://zenodo.org/record/3838216>`_.
 
 Sphinx-Gallery Show: :ref:`examples-index`
 ------------------------------------------
diff --git a/setup.py b/setup.py
index 7b120c8..f6acd3d 100644
--- a/setup.py
+++ b/setup.py
@@ -44,6 +44,7 @@ setup(
         '_static/gallery-dataframe.css',
         '_static/no_image.png',
         '_static/broken_example.png',
+        '_static/binder_badge_logo.svg'
     ]},
     scripts=['bin/copy_sphinxgallery.sh', 'bin/sphx_glr_python_to_jupyter.py'],
     url="https://sphinx-gallery.github.io",
diff --git a/sphinx_gallery/_static/binder_badge_logo.svg b/sphinx_gallery/_static/binder_badge_logo.svg
new file mode 100644
index 0000000..327f6b6
--- /dev/null
+++ b/sphinx_gallery/_static/binder_badge_logo.svg
@@ -0,0 +1,1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="109" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="109" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h64v20H0z"/><path fill="#579aca" d="M64 0h45v20H64z"/><path fill="url(#b)" d="M0 0h109v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/png;base64,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"/> <text x="415" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">launch</text><text x="415" y="140" transform="scale(.1)" textLength="370">launch</text><text x="855" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">binder</text><text x="855" y="140" transform="scale(.1)" textLength="350">binder</text></g> </svg>
\ No newline at end of file
diff --git a/sphinx_gallery/binder.py b/sphinx_gallery/binder.py
index a09c882..d4a04a6 100644
--- a/sphinx_gallery/binder.py
+++ b/sphinx_gallery/binder.py
@@ -22,6 +22,7 @@ from sphinx.errors import ConfigError
 
 from .utils import replace_py_ipynb
 from . import sphinx_compatibility
+from . import glr_path_static
 
 
 logger = sphinx_compatibility.getLogger('sphinx-gallery')
@@ -81,6 +82,7 @@ def gen_binder_rst(fpath, binder_conf, gallery_conf):
     ----------
     fpath: str
         The path to the `.py` file for which a Binder badge will be generated.
+
     binder_conf: dict or None
         If a dictionary it must have the following keys:
 
@@ -95,6 +97,9 @@ def gen_binder_rst(fpath, binder_conf, gallery_conf):
         'dependencies'
             A list of paths to dependency files that match the Binderspec.
 
+    gallery_conf : dict
+        Sphinx-Gallery configuration dictionary.
+
     Returns
     -------
     rst : str
@@ -103,12 +108,15 @@ def gen_binder_rst(fpath, binder_conf, gallery_conf):
     binder_conf = check_binder_conf(binder_conf)
     binder_url = gen_binder_url(fpath, binder_conf, gallery_conf)
 
+    binder_logo = os.path.join(glr_path_static(), 'binder_badge_logo.svg')
+    binder_logo_path = os.path.relpath(binder_logo, gallery_conf['src_dir'])
+
     rst = (
         "\n"
         "  .. container:: binder-badge\n\n"
-        "    .. image:: https://mybinder.org/badge_logo.svg\n"
+        "    .. image:: /{}\n"
         "      :target: {}\n"
-        "      :width: 150 px\n").format(binder_url)
+        "      :width: 150 px\n").format(binder_logo_path, binder_url)
     return rst
 
 


Test patch:
diff --git a/sphinx_gallery/tests/test_binder.py b/sphinx_gallery/tests/test_binder.py
index fba39f4..42d9f40 100644
--- a/sphinx_gallery/tests/test_binder.py
+++ b/sphinx_gallery/tests/test_binder.py
@@ -6,13 +6,15 @@ Testing the binder badge functionality
 """
 from __future__ import division, absolute_import, print_function
 
+import os
 from copy import deepcopy
 
 import pytest
 
+from sphinx_gallery.__init__ import glr_path_static
 from sphinx.errors import ConfigError
 from sphinx_gallery.binder import (gen_binder_url, check_binder_conf,
-                                   _copy_binder_reqs)
+                                   _copy_binder_reqs, gen_binder_rst)
 
 
 def test_binder():
@@ -113,3 +115,21 @@ def test_binder():
     expected = ('http://test1.com/v2/gh/org/repo/'
                 'branch?filepath=ntbk_folder/mydir/myfolder/myfile.ipynb')
     assert url == expected
+
+
+def test_gen_binder_rst():
+    """Check binder rst generated correctly."""
+    gallery_conf_base = {'gallery_dirs': 'mydir', 'src_dir': 'blahblah'}
+    file_path = 'blahblah/mydir/myfile.py'
+    conf_base = {'binderhub_url': 'http://test1.com', 'org': 'org',
+                 'repo': 'repo', 'branch': 'branch',
+                 'dependencies': '../requirements.txt'}
+
+    rst = gen_binder_rst(file_path, conf_base, gallery_conf_base)
+    binder_logo = os.path.join(glr_path_static(), 'binder_badge_logo.svg')
+    binder_logo_path = os.path.relpath(binder_logo, 'blahblah')
+
+    image_rst = (' .. image:: /{}').format(binder_logo_path)
+    target_rst = ':target: http://test1.com/v2/gh/org/repo/branch?filepath=notebooks/mydir/myfile.ipynb'  # noqa E501
+    assert image_rst in rst
+    assert target_rst in rst
diff --git a/sphinx_gallery/tests/test_full.py b/sphinx_gallery/tests/test_full.py
index 87f1213..2884f3e 100644
--- a/sphinx_gallery/tests/test_full.py
+++ b/sphinx_gallery/tests/test_full.py
@@ -18,6 +18,7 @@ import time
 import numpy as np
 from numpy.testing import assert_allclose
 
+from sphinx_gallery.__init__ import glr_path_static
 from sphinx.application import Sphinx
 from sphinx.errors import ExtensionError
 from sphinx.util.docutils import docutils_namespace
@@ -812,3 +813,12 @@ def test_md5_hash(sphinx_app):
         actual_md5 = md5_file.read()
 
     assert actual_md5 == expected_md5
+
+
+def test_binder_logo_exists(sphinx_app):
+    """Check that the binder logo path is correct."""
+    src_dir = sphinx_app.srcdir
+    binder_logo = os.path.join(glr_path_static(), 'binder_badge_logo.svg')
+    binder_logo_path = os.path.relpath(binder_logo, src_dir)
+
+    assert op.isfile('/{}'.format(binder_logo_path))