kopia lustrzana https://github.com/simonw/datasette
script type=module support, closes #1186
rodzic
640ac7071b
commit
fa0c3777b8
|
|
@ -864,19 +864,23 @@ class Datasette:
|
|||
if isinstance(url_or_dict, dict):
|
||||
url = url_or_dict["url"]
|
||||
sri = url_or_dict.get("sri")
|
||||
module = bool(url_or_dict.get("module"))
|
||||
else:
|
||||
url = url_or_dict
|
||||
sri = None
|
||||
module = False
|
||||
if url in seen_urls:
|
||||
continue
|
||||
seen_urls.add(url)
|
||||
if url.startswith("/"):
|
||||
# Take base_url into account:
|
||||
url = self.urls.path(url)
|
||||
script = {"url": url}
|
||||
if sri:
|
||||
output.append({"url": url, "sri": sri})
|
||||
else:
|
||||
output.append({"url": url})
|
||||
script["sri"] = sri
|
||||
if module:
|
||||
script["module"] = True
|
||||
output.append(script)
|
||||
return output
|
||||
|
||||
def app(self):
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<link rel="stylesheet" href="{{ url.url }}"{% if url.sri %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}>
|
||||
{% endfor %}
|
||||
{% for url in extra_js_urls %}
|
||||
<script src="{{ url.url }}"{% if url.sri %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}></script>
|
||||
<script {% if url.module %}type="module" {% endif %}src="{{ url.url }}"{% if url.sri %} integrity="{{ url.sri }}" crossorigin="anonymous"{% endif %}></script>
|
||||
{% endfor %}
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ Custom pages and templates
|
|||
|
||||
Datasette provides a number of ways of customizing the way data is displayed.
|
||||
|
||||
.. _customization_css_and_javascript:
|
||||
|
||||
Custom CSS and JavaScript
|
||||
-------------------------
|
||||
|
||||
|
|
@ -25,7 +27,12 @@ Your ``metadata.json`` file can include links that look like this:
|
|||
]
|
||||
}
|
||||
|
||||
The extra CSS and JavaScript files will be linked in the ``<head>`` of every page.
|
||||
The extra CSS and JavaScript files will be linked in the ``<head>`` of every page:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<link rel="stylesheet" href="https://simonwillison.net/static/css/all.bf8cd891642c.css">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
|
||||
|
||||
You can also specify a SRI (subresource integrity hash) for these assets:
|
||||
|
||||
|
|
@ -46,9 +53,39 @@ You can also specify a SRI (subresource integrity hash) for these assets:
|
|||
]
|
||||
}
|
||||
|
||||
This will produce:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<link rel="stylesheet" href="https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
||||
integrity="sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
|
||||
crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
Modern browsers will only execute the stylesheet or JavaScript if the SRI hash
|
||||
matches the content served. You can generate hashes using `www.srihash.org <https://www.srihash.org/>`_
|
||||
|
||||
Items in ``"extra_js_urls"`` can specify ``"module": true`` if they reference JavaScript that uses `JavaScript modules <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`__. This configuration:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"extra_js_urls": [
|
||||
{
|
||||
"url": "https://example.datasette.io/module.js",
|
||||
"module": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Will produce this HTML:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<script type="module" src="https://example.datasette.io/module.js"></script>
|
||||
|
||||
CSS classes on the <body>
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ This can be a list of URLs:
|
|||
@hookimpl
|
||||
def extra_css_urls():
|
||||
return [
|
||||
'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css'
|
||||
"https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
|
||||
]
|
||||
|
||||
Or a list of dictionaries defining both a URL and an
|
||||
|
|
@ -190,21 +190,17 @@ Or a list of dictionaries defining both a URL and an
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from datasette import hookimpl
|
||||
|
||||
@hookimpl
|
||||
def extra_css_urls():
|
||||
return [{
|
||||
'url': 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css',
|
||||
'sri': 'sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4',
|
||||
"url": "https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css",
|
||||
"sri": "sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4",
|
||||
}]
|
||||
|
||||
This function can also return an awaitable function, useful if it needs to run any async code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from datasette import hookimpl
|
||||
|
||||
@hookimpl
|
||||
def extra_css_urls(datasette):
|
||||
async def inner():
|
||||
|
|
@ -233,8 +229,8 @@ return a list of URLs, a list of dictionaries or an awaitable function that retu
|
|||
@hookimpl
|
||||
def extra_js_urls():
|
||||
return [{
|
||||
'url': 'https://code.jquery.com/jquery-3.3.1.slim.min.js',
|
||||
'sri': 'sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo',
|
||||
"url": "https://code.jquery.com/jquery-3.3.1.slim.min.js",
|
||||
"sri": "sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo",
|
||||
}]
|
||||
|
||||
You can also return URLs to files from your plugin's ``static/`` directory, if
|
||||
|
|
@ -242,12 +238,21 @@ you have one:
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from datasette import hookimpl
|
||||
|
||||
@hookimpl
|
||||
def extra_js_urls():
|
||||
return [
|
||||
'/-/static-plugins/your-plugin/app.js'
|
||||
"/-/static-plugins/your-plugin/app.js"
|
||||
]
|
||||
|
||||
If your code uses `JavaScript modules <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`__ you should include the ``"module": True`` key. See :ref:`customization_css_and_javascript` for more details.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@hookimpl
|
||||
def extra_js_urls():
|
||||
return [{
|
||||
"url": "/-/static-plugins/your-plugin/app.js",
|
||||
"module": True
|
||||
]
|
||||
|
||||
Examples: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_, `datasette-vega <https://github.com/simonw/datasette-vega>`_
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ def extra_js_urls():
|
|||
"sri": "SRIHASH",
|
||||
},
|
||||
"https://plugin-example.datasette.io/plugin1.js",
|
||||
{"url": "https://plugin-example.datasette.io/plugin.module.js", "module": True},
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -118,16 +118,19 @@ def test_hook_extra_css_urls(app_client, path, expected_decoded_object):
|
|||
def test_hook_extra_js_urls(app_client):
|
||||
response = app_client.get("/")
|
||||
scripts = Soup(response.body, "html.parser").findAll("script")
|
||||
assert [
|
||||
s
|
||||
for s in scripts
|
||||
if s.attrs
|
||||
== {
|
||||
script_attrs = [s.attrs for s in scripts]
|
||||
for attrs in [
|
||||
{
|
||||
"integrity": "SRIHASH",
|
||||
"crossorigin": "anonymous",
|
||||
"src": "https://plugin-example.datasette.io/jquery.js",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"src": "https://plugin-example.datasette.io/plugin.module.js",
|
||||
"type": "module",
|
||||
},
|
||||
]:
|
||||
assert any(s == attrs for s in script_attrs), "Expected: {}".format(attrs)
|
||||
|
||||
|
||||
def test_plugins_with_duplicate_js_urls(app_client):
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue