[fix] plugin JS/CSS dependencies depend on themes

SearXNG supports plugins. Plugins can declare JavaScript and CSS
dependencies. Currently three plugins declare such dependencies:

* search_on_category_select (on by default)
* vim_hotkeys
* infinite_scroll

If a user enables a plugin its JavaScript and CSS dependencies are
embedded into every page. Sounds simple right?

Ironically in the Simple theme things start to get complicated:
The scripts were originally written for the Oscar theme and thus depend
on jQuery (which isn't loaded in the Simple theme) and look for certain
element identifiers (which aren't present in the Simple theme).  So how
did the plugins actually work with the simple theme?

The simple theme just didn't embed the plugin dependencies (which wasn't
even documented anywhere). Instead the simple theme checked if the paths
contained a certain script path, then set an attribute, which 00_init.js
detected and turned into a boolean, which was then used to enable
vanilla-JS reimplementations of the plugins.

This commit ends this horrible hack (and fixes #769).  The necessary
changes to the Simple theme are introduced in the next commit.
This commit is contained in:
Martin Fischer 2022-01-18 17:45:08 +01:00
parent 2142bc5c3a
commit 3f77ff29a3
7 changed files with 37 additions and 13 deletions

View file

@ -15,12 +15,14 @@ Example plugin
.. code:: python
from . import Resource
name = 'Example plugin'
description = 'This plugin extends the suggestions with the word "example"'
default_on = False # disabled by default
js_dependencies = tuple() # optional, list of static js files
css_dependencies = tuple() # optional, list of static css files
js_dependencies = tuple() # optional, list of static js resources
css_dependencies = tuple() # optional, list of static css resources
# attach callback to the post search hook

View file

@ -10,7 +10,7 @@ from os.path import abspath, basename, dirname, exists, join
from shutil import copyfile
from pkgutil import iter_modules
from logging import getLogger
from typing import List, Tuple
from typing import List, Tuple, NamedTuple
from searx import logger, settings
@ -22,11 +22,18 @@ class Plugin: # pylint: disable=too-few-public-methods
name: str
description: str
default_on: bool
js_dependencies: Tuple[str]
css_dependencies: Tuple[str]
js_dependencies: Tuple['Resource']
css_dependencies: Tuple['Resource']
preference_section: str
class Resource(NamedTuple):
path: str
""" The path to the file """
themes: Tuple[str]
""" For which themes the file should be loaded """
logger = logger.getChild("plugins")
required_attrs = (

View file

@ -1,9 +1,10 @@
from flask_babel import gettext
from . import Resource
name = gettext('Infinite scroll')
description = gettext('Automatically load next page when scrolling to bottom of current page')
default_on = False
preference_section = 'ui'
js_dependencies = ('plugins/js/infinite_scroll.js',)
css_dependencies = ('plugins/css/infinite_scroll.css',)
js_dependencies = (Resource(path='plugins/js/infinite_scroll.js', themes=('oscar',)),)
css_dependencies = (Resource(path='plugins/css/infinite_scroll.css', themes=('oscar',)),)

View file

@ -15,6 +15,7 @@ along with searx. If not, see < http://www.gnu.org/licenses/ >.
(C) 2015 by Adam Tauber, <asciimoo@gmail.com>
'''
from flask_babel import gettext
from . import Resource
name = gettext('Search on category select')
description = gettext(
@ -23,4 +24,6 @@ description = gettext(
default_on = True
preference_section = 'ui'
js_dependencies = ('plugins/js/search_on_category_select.js',)
js_dependencies = (
Resource(path='plugins/js/search_on_category_select.js', themes=('oscar',)),
)

View file

@ -1,4 +1,5 @@
from flask_babel import gettext
from . import Resource
name = gettext('Vim-like hotkeys')
description = gettext(
@ -9,5 +10,7 @@ description = gettext(
default_on = False
preference_section = 'ui'
js_dependencies = ('plugins/js/vim_hotkeys.js',)
css_dependencies = ('plugins/css/vim_hotkeys.css',)
js_dependencies = (
Resource(path='plugins/js/vim_hotkeys.js', themes=('oscar',)),
)
css_dependencies = (Resource(path='plugins/css/vim_hotkeys.css', themes=('oscar',)),)

View file

@ -17,6 +17,9 @@
{% else %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/searxng.min.css') }}" type="text/css" media="screen" />
{% endif %}
{%- for css in styles %}
<link rel="stylesheet" href="{{ url_for('static', filename=css) }}" type="text/css" />
{% endfor %}
{% block styles %}{% endblock %}
<script src="{{ url_for('static', filename='js/searxng.head.min.js') }}"
data-method="{{ method or 'POST' }}"
@ -59,5 +62,8 @@
</p>
</footer>
<script src="{{ url_for('static', filename='js/searxng.min.js') }}"></script>
{% for script in scripts %}
<script src="{{ url_for('static', filename=script) }}"></script>
{% endfor %}
</body>
</html>

View file

@ -456,7 +456,7 @@ def render(template_name: str, override_theme: str = None, **kwargs):
kwargs['advanced_search'] = request.preferences.get_value('advanced_search')
kwargs['query_in_title'] = request.preferences.get_value('query_in_title')
kwargs['safesearch'] = str(request.preferences.get_value('safesearch'))
kwargs['theme'] = get_current_theme_name(override=override_theme)
kwargs['theme'] = current_theme = get_current_theme_name(override=override_theme)
kwargs['categories_as_tabs'] = list(settings['categories_as_tabs'].keys())
kwargs['categories'] = _get_enable_categories(categories.keys())
kwargs['OTHER_CATEGORY'] = OTHER_CATEGORY
@ -497,13 +497,15 @@ def render(template_name: str, override_theme: str = None, **kwargs):
kwargs['scripts'] = set()
for plugin in request.user_plugins:
for script in plugin.js_dependencies:
kwargs['scripts'].add(script)
if current_theme in script.themes:
kwargs['scripts'].add(script.path)
# styles from plugins
kwargs['styles'] = set()
for plugin in request.user_plugins:
for css in plugin.css_dependencies:
kwargs['styles'].add(css)
if current_theme in css.themes:
kwargs['styles'].add(css.path)
start_time = default_timer()
result = render_template('{}/{}'.format(kwargs['theme'], template_name), **kwargs)