kopia lustrzana https://github.com/simonw/datasette
				
				
				
			
							rodzic
							
								
									ca588b6a30
								
							
						
					
					
						commit
						1c36d07dd4
					
				|  | @ -12,6 +12,7 @@ import asyncio | |||
| import os | ||||
| import threading | ||||
| import urllib.parse | ||||
| import itertools | ||||
| import json | ||||
| import jinja2 | ||||
| import hashlib | ||||
|  | @ -1126,7 +1127,12 @@ class Datasette: | |||
|             } | ||||
| 
 | ||||
|     def asset_urls(self, key): | ||||
|         for url_or_dict in (self.metadata.get(key) or []): | ||||
|         urls_or_dicts = (self.metadata.get(key) or []) | ||||
|         # Flatten list-of-lists from plugins: | ||||
|         urls_or_dicts += list( | ||||
|             itertools.chain.from_iterable(getattr(pm.hook, key)()) | ||||
|         ) | ||||
|         for url_or_dict in urls_or_dicts: | ||||
|             if isinstance(url_or_dict, dict): | ||||
|                 yield { | ||||
|                     'url': url_or_dict['url'], | ||||
|  | @ -1297,10 +1303,14 @@ class Datasette: | |||
|             app.static(path, dirname) | ||||
|         # Mount any plugin static/ directories | ||||
|         for plugin_module in pm.get_plugins(): | ||||
|             if pkg_resources.resource_isdir(plugin_module.__name__, 'static'): | ||||
|                 modpath = '/-/static-plugins/{}/'.format(plugin_module.__name__) | ||||
|                 dirpath = pkg_resources.resource_filename(plugin_module.__name__, 'static') | ||||
|                 app.static(modpath, dirpath) | ||||
|             try: | ||||
|                 if pkg_resources.resource_isdir(plugin_module.__name__, 'static'): | ||||
|                     modpath = '/-/static-plugins/{}/'.format(plugin_module.__name__) | ||||
|                     dirpath = pkg_resources.resource_filename(plugin_module.__name__, 'static') | ||||
|                     app.static(modpath, dirpath) | ||||
|             except ModuleNotFoundError: | ||||
|                 # Caused by --plugins_dir= plugins | ||||
|                 pass | ||||
|         app.add_route( | ||||
|             DatabaseView.as_view(self), | ||||
|             '/<db_name:[^/\.]+?><as_json:(\.jsono?)?$>' | ||||
|  |  | |||
|  | @ -13,3 +13,13 @@ def prepare_connection(conn): | |||
| @hookspec | ||||
| def prepare_jinja2_environment(env): | ||||
|     "Modify Jinja2 template environment e.g. register custom template tags" | ||||
| 
 | ||||
| 
 | ||||
| @hookspec | ||||
| def extra_css_urls(): | ||||
|     "Extra CSS URLs added by this plugin" | ||||
| 
 | ||||
| 
 | ||||
| @hookspec | ||||
| def extra_js_urls(): | ||||
|     "Extra JavaScript URLs added by this plugin" | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| Customizing Datasette's appearance | ||||
| ================================== | ||||
| .. _customization: | ||||
| 
 | ||||
| Customization | ||||
| ============= | ||||
| 
 | ||||
| Datasette provides a number of ways of customizing the way data is displayed. | ||||
| 
 | ||||
|  |  | |||
|  | @ -169,3 +169,65 @@ example: | |||
| You can now use this filter in your custom templates like so:: | ||||
| 
 | ||||
|     Table name: {{ table|uppercase }} | ||||
| 
 | ||||
| extra_css_urls() | ||||
| ~~~~~~~~~~~~~~~~ | ||||
| 
 | ||||
| Return a list of extra CSS URLs that should be included on every page. These can | ||||
| take advantage of the CSS class hooks described in :ref:`customization`. | ||||
| 
 | ||||
| This can be a list of URLs: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from datasette import hookimpl | ||||
| 
 | ||||
|     @hookimpl | ||||
|     def extra_css_urls(): | ||||
|         return [ | ||||
|             'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css' | ||||
|         ] | ||||
| 
 | ||||
| Or a list of dictionaries defining both a URL and an | ||||
| `SRI hash <https://www.srihash.org/>`_: | ||||
| 
 | ||||
| .. 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', | ||||
|         }] | ||||
| 
 | ||||
| extra_js_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: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from datasette import hookimpl | ||||
| 
 | ||||
|     @hookimpl | ||||
|     def extra_js_urls(): | ||||
|         return [{ | ||||
|             '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 | ||||
| you have one: | ||||
| 
 | ||||
| .. code-block:: python | ||||
| 
 | ||||
|     from datasette import hookimpl | ||||
| 
 | ||||
|     @hookimpl | ||||
|     def extra_js_urls(): | ||||
|         return [ | ||||
|             '/-/static-plugins/your_plugin/app.js' | ||||
|         ] | ||||
|  |  | |||
|  | @ -113,6 +113,19 @@ def prepare_connection(conn): | |||
|         "select convert_units(100, 'm', 'ft');" | ||||
|         return (amount * ureg(from_)).to(to_).to_tuple()[0] | ||||
|     conn.create_function('convert_units', 3, convert_units) | ||||
| 
 | ||||
| 
 | ||||
| @hookimpl | ||||
| def extra_css_urls(): | ||||
|     return ['https://example.com/app.css'] | ||||
| 
 | ||||
| 
 | ||||
| @hookimpl | ||||
| def extra_js_urls(): | ||||
|     return [{ | ||||
|         'url': 'https://example.com/app.js', | ||||
|         'sri': 'SRIHASH', | ||||
|     }] | ||||
| ''' | ||||
| 
 | ||||
| TABLES = ''' | ||||
|  |  | |||
|  | @ -333,6 +333,19 @@ def test_view_html(app_client): | |||
|     assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')] | ||||
| 
 | ||||
| 
 | ||||
| def test_plugin_extra_css_urls(app_client): | ||||
|     response = app_client.get('/', gather_request=False) | ||||
|     assert b'<link rel="stylesheet" href="https://example.com/app.css">' in response.body | ||||
| 
 | ||||
| 
 | ||||
| def test_plugin_extra_js_urls(app_client): | ||||
|     response = app_client.get('/', gather_request=False) | ||||
|     assert ( | ||||
|         b'<script src="https://example.com/app.js" integrity="SRIHASH" crossorigin="anonymous"></script>' | ||||
|         in response.body | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def test_index_metadata(app_client): | ||||
|     response = app_client.get('/', gather_request=False) | ||||
|     assert response.status == 200 | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Simon Willison
						Simon Willison