Browse Source

Allow hooks to be called in templates

Peter Justin 7 years ago
parent
commit
2bb6b4b0b4

+ 3 - 1
flaskbb/app.py

@@ -54,7 +54,7 @@ from flaskbb.utils.settings import flaskbb_config
 
 from flaskbb.plugins.models import PluginRegistry
 from flaskbb.plugins.manager import FlaskBBPluginManager
-from flaskbb.plugins.utils import remove_zombie_plugins_from_db
+from flaskbb.plugins.utils import remove_zombie_plugins_from_db, template_hook
 from flaskbb.plugins import spec
 
 
@@ -238,6 +238,8 @@ def configure_template_filters(app):
 
     app.jinja_env.filters.update(filters)
 
+    app.jinja_env.globals["run_hook"] = template_hook
+
     app.pluggy.hook.flaskbb_jinja_directives(app=app)
 
 

+ 5 - 0
flaskbb/plugins/spec.py

@@ -76,3 +76,8 @@ def flaskbb_cli(cli):
     """
     Hook for registering CLI commands
     """
+
+
+@spec
+def flaskbb_tpl_before_navigation():
+    """Hook for registering additional navigation items."""

+ 21 - 0
flaskbb/plugins/utils.py

@@ -10,12 +10,33 @@
     :license: BSD, see LICENSE for more details.
 """
 from flask import current_app, flash, redirect, url_for
+from jinja2 import Markup
 from flask_babelplus import gettext as _
 
 from flaskbb.extensions import db
+from flaskbb.utils.datastructures import TemplateEventResult
 from flaskbb.plugins.models import PluginRegistry
 
 
+def template_hook(name, silent=True, **kwargs):
+    """Calls the given template hook.
+
+    :param name: The name of the hook.
+    :param silent: If set to ``False``, it will raise an exception if a hook
+                   doesn't exist. Defauls to ``True``.
+    :param kwargs: Additional kwargs that should be passed to the hook.
+    """
+    try:
+        hook = getattr(current_app.pluggy.hook, name)
+        result = hook(**kwargs)
+    except AttributeError:  # raised if hook doesn't exist
+        if silent:
+            return ""
+        raise
+
+    return Markup(TemplateEventResult(result))
+
+
 def validate_plugin(name):
     """Tries to look up the plugin by name. Upon failure it will flash
     a message and abort. Returns the plugin module on success.

+ 2 - 1
flaskbb/templates/layout.html

@@ -71,10 +71,11 @@
                         <ul class="nav navbar-nav forum-nav">
                             {%- from theme("macros.html") import is_active, topnav with context -%}
 
+                            {{ run_hook("flaskbb_tpl_before_navigation") }}
                             {{ topnav(endpoint='forum.index', name=_('Forum'), icon='fa fa-comment', active=active_forum_nav) }}
                             {{ topnav(endpoint='forum.memberlist', name=_('Memberlist'), icon='fa fa-user') }}
                             {{ topnav(endpoint='forum.search', name=_('Search'), icon='fa fa-search') }}
-
+                            {{ run_hook("flaskbb_tpl_after_navigation") }}
                         </ul>
 
                         <!-- navbar right -->

+ 19 - 2
flaskbb/utils/datastructures.py

@@ -8,11 +8,10 @@
     :copyright: (c) 2014 by the FlaskBB Team.
     :license: BSD, see LICENSE for more details.
 """
+import sys
 try:
     from types import SimpleNamespace
-
 except ImportError:
-
     class SimpleNamespace(dict):
 
         def __getattr__(self, name):
@@ -24,3 +23,21 @@ except ImportError:
 
         def __setattr__(self, name, value):
             super(SimpleNamespace, self).__setitem__(name, value)
+
+
+class TemplateEventResult(list):
+    """A list subclass for results returned by the hook that
+    concatenates the results if converted to string, otherwise it works
+    exactly like any other list.
+    """
+
+    def __init__(self, items):
+        list.__init__(self, items)
+
+    def __unicode__(self):
+        return u"".join(map(str, self))
+
+    def __str__(self):
+        if sys.version_info[0] >= 3:
+            return self.__unicode__()
+        return self.__unicode__().encode("utf-8")