extra_css_urls(template, database, table, datasette)

The extra_css_urls and extra_js_urls hooks now take additional optional
parameters.

Also refactored them out of the Datasette class and into RenderMixin.

Plus improved plugin documentation to explicitly list parameters.
pull/363/head
Simon Willison 2018-08-28 11:56:57 +01:00
rodzic fbf446965b
commit b7c6a9f9bd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 17E2DEA2588B7F52
7 zmienionych plików z 124 dodań i 52 usunięć

Wyświetl plik

@ -2,7 +2,6 @@ import asyncio
import click
import collections
import hashlib
import itertools
import os
import sys
import threading
@ -258,33 +257,6 @@ class Datasette:
def get_view_definition(self, database_name, view):
return self.get_table_definition(database_name, view, 'view')
def asset_urls(self, key):
# Flatten list-of-lists from plugins:
seen_urls = set()
for url_or_dict in itertools.chain(
itertools.chain.from_iterable(getattr(pm.hook, key)()),
(self.metadata(key) or [])
):
if isinstance(url_or_dict, dict):
url = url_or_dict["url"]
sri = url_or_dict.get("sri")
else:
url = url_or_dict
sri = None
if url in seen_urls:
continue
seen_urls.add(url)
if sri:
yield {"url": url, "sri": sri}
else:
yield {"url": url}
def extra_css_urls(self):
return self.asset_urls("extra_css_urls")
def extra_js_urls(self):
return self.asset_urls("extra_js_urls")
def update_with_inherited_metadata(self, metadata):
# Fills in source/license with defaults, if available
metadata.update(

Wyświetl plik

@ -16,12 +16,12 @@ def prepare_jinja2_environment(env):
@hookspec
def extra_css_urls():
def extra_css_urls(template, database, table, datasette):
"Extra CSS URLs added by this plugin"
@hookspec
def extra_js_urls():
def extra_js_urls(template, database, table, datasette):
"Extra JavaScript URLs added by this plugin"

Wyświetl plik

@ -1,5 +1,6 @@
import asyncio
import csv
import itertools
import json
import re
import time
@ -46,6 +47,32 @@ class DatasetteError(Exception):
class RenderMixin(HTTPMethodView):
def _asset_urls(self, key, template, context):
# Flatten list-of-lists from plugins:
seen_urls = set()
for url_or_dict in itertools.chain(
itertools.chain.from_iterable(getattr(pm.hook, key)(
template=template.name,
database=context.get("database"),
table=context.get("table"),
datasette=self.ds
)),
(self.ds.metadata(key) or [])
):
if isinstance(url_or_dict, dict):
url = url_or_dict["url"]
sri = url_or_dict.get("sri")
else:
url = url_or_dict
sri = None
if url in seen_urls:
continue
seen_urls.add(url)
if sri:
yield {"url": url, "sri": sri}
else:
yield {"url": url}
def render(self, templates, **context):
template = self.ds.jinja_env.select_template(templates)
select_templates = [
@ -69,6 +96,12 @@ class RenderMixin(HTTPMethodView):
"select_templates": select_templates,
"zip": zip,
"body_scripts": body_scripts,
"extra_css_urls": self._asset_urls(
"extra_css_urls", template, context
),
"extra_js_urls": self._asset_urls(
"extra_js_urls", template, context
),
}
}
)
@ -432,8 +465,6 @@ class BaseView(RenderMixin):
"url_csv": url_csv,
"url_csv_path": url_csv_path,
"url_csv_args": url_csv_args,
"extra_css_urls": self.ds.extra_css_urls(),
"extra_js_urls": self.ds.extra_js_urls(),
"datasette_version": __version__,
"config": self.ds.config_dict(),
}

Wyświetl plik

@ -51,6 +51,4 @@ class IndexView(RenderMixin):
databases=databases,
metadata=self.ds.metadata(),
datasette_version=__version__,
extra_css_urls=self.ds.extra_css_urls(),
extra_js_urls=self.ds.extra_js_urls(),
)

Wyświetl plik

@ -231,6 +231,9 @@ The full list of available plugin hooks is as follows.
prepare_connection(conn)
~~~~~~~~~~~~~~~~~~~~~~~~
``conn`` - sqlite3 connection object
The connection that is being opened
This hook is called when a new SQLite database connection is created. You can
use it to `register custom SQL functions <https://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.create_function>`_,
aggregates and collations. For example:
@ -252,6 +255,9 @@ arguments and can be called like this::
prepare_jinja2_environment(env)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``env`` - jinja2 Environment
The template environment that is being prepared
This hook is called with the Jinja2 environment that is used to evaluate
Datasette HTML templates. You can use it to do things like `register custom
template filters <http://jinja.pocoo.org/docs/2.10/api/#custom-filters>`_, for
@ -269,10 +275,22 @@ You can now use this filter in your custom templates like so::
Table name: {{ table|uppercase }}
extra_css_urls()
~~~~~~~~~~~~~~~~
extra_css_urls(template, database, table, datasette)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Return a list of extra CSS URLs that should be included on every page. These can
``template`` - string
The template that is being rendered, e.g. ``database.html``
``database`` - string or None
The name of the database
``table`` - string or None
The name of the table
``datasette`` - Datasette instance
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
Return a list of extra CSS URLs that should be included on the page. These can
take advantage of the CSS class hooks described in :ref:`customization`.
This can be a list of URLs:
@ -301,8 +319,10 @@ Or a list of dictionaries defining both a URL and an
'sri': 'sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4',
}]
extra_js_urls()
~~~~~~~~~~~~~~~
extra_js_urls(template, database, table, datasette)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Same arguments as ``extra_css_urls``.
This works in the same way as ``extra_css_urls()`` but for JavaScript. You can
return either a list of URLs or a list of dictionaries:
@ -334,6 +354,9 @@ you have one:
publish_subcommand(publish)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
``publish`` - Click publish command group
The Click command group for the ``datasette publish`` subcommand
This hook allows you to create new providers for the ``datasette publish``
command. Datasette uses this hook internally to implement the default ``now``
and ``heroku`` subcommands, so you can read
@ -351,8 +374,8 @@ Lets you customize the display of values within table cells in the HTML table vi
``column`` - string
The name of the column being rendered
``table`` - string
The name of the table
``table`` - string or None
The name of the table - or ``None`` if this is a custom SQL query
``database`` - string
The name of the database
@ -411,6 +434,18 @@ If the value matches that pattern, the plugin returns an HTML link element:
extra_body_script(template, database, table, datasette)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``template`` - string
The template that is being rendered, e.g. ``database.html``
``database`` - string or None
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
``table`` - string or None
The name of the table, or ``None`` if the page does not correct to a table
``datasette`` - Datasette instance
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
Extra JavaScript to be added to a ``<script>`` block at the end of the ``<body>`` element on the page.
The ``template``, ``database`` and ``table`` options can be used to return different code depending on which template is being rendered and which database or table are being processed.

Wyświetl plik

@ -204,6 +204,7 @@ METADATA = {
PLUGIN1 = '''
from datasette import hookimpl
import base64
import pint
import json
@ -219,8 +220,14 @@ def prepare_connection(conn):
@hookimpl
def extra_css_urls():
return ['https://example.com/app.css']
def extra_css_urls(template, database, table, datasette):
return ['https://example.com/{}/extra-css-urls-demo.css'.format(
base64.b64encode(json.dumps({
"template": template,
"database": database,
"table": table,
}).encode("utf8")).decode("utf8")
)]
@hookimpl

Wyświetl plik

@ -2,6 +2,7 @@ from bs4 import BeautifulSoup as Soup
from .fixtures import ( # noqa
app_client,
)
import base64
import json
import re
import pytest
@ -15,16 +16,44 @@ def test_plugins_dir_plugin(app_client):
assert pytest.approx(328.0839) == response.json['rows'][0][0]
def test_plugin_extra_css_urls(app_client):
response = app_client.get('/')
@pytest.mark.parametrize(
"path,expected_decoded_object",
[
(
"/",
{
"template": "index.html",
"database": None,
"table": None,
},
),
(
"/fixtures/",
{
"template": "database.html",
"database": "fixtures",
"table": None,
},
),
(
"/fixtures/sortable",
{
"template": "table.html",
"database": "fixtures",
"table": "sortable",
},
),
],
)
def test_plugin_extra_css_urls(app_client, path, expected_decoded_object):
response = app_client.get(path)
links = Soup(response.body, 'html.parser').findAll('link')
assert [
l for l in links
if l.attrs == {
'rel': ['stylesheet'],
'href': 'https://example.com/app.css'
}
]
special_href = [
l for l in links if l.attrs["href"].endswith("/extra-css-urls-demo.css")
][0]["href"]
# This link has a base64-encoded JSON blob in it
encoded = special_href.split("/")[3]
assert expected_decoded_object == json.loads(base64.b64decode(encoded))
def test_plugin_extra_js_urls(app_client):