diff --git a/community/hooks.py b/community/hooks.py index fba4d694..0727f9ca 100644 --- a/community/hooks.py +++ b/community/hooks.py @@ -169,3 +169,5 @@ profile_rules = [ ] website_route_rules = primary_rules + whitelist_rules + profile_rules + +update_website_context = 'community.widgets.update_website_context' diff --git a/community/lms/widgets/HelloWorld.html b/community/lms/widgets/HelloWorld.html new file mode 100644 index 00000000..a8e09c01 --- /dev/null +++ b/community/lms/widgets/HelloWorld.html @@ -0,0 +1,14 @@ +{# + Widget to demonostrate how to write a widget. + + A wiget is a reusable template, that can be used in + other templates. + + To this widget can be called as: + + {{ widgets.HelloWorld(name="World") }} +#} + +
+ Hello, {{ name }}! +
diff --git a/community/test_widgets.py b/community/test_widgets.py new file mode 100644 index 00000000..7d810472 --- /dev/null +++ b/community/test_widgets.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021, FOSS United and Contributors +# See license.txt +import frappe +import unittest +from .widgets import Widget, Widgets + +class TestWidgets(unittest.TestCase): + def test_Widgets(self): + widgets = Widgets() + assert widgets.Foo.name == "Foo" + assert widgets.Bar.name == "Bar" + + def _test_Widget(self): + hello = Widget("HelloWorld") + assert hello(name="Test") == "Hello, Test" diff --git a/community/widgets.py b/community/widgets.py new file mode 100644 index 00000000..b5475ecc --- /dev/null +++ b/community/widgets.py @@ -0,0 +1,60 @@ +"""The widgets provides access to HTML widgets +provided in each frappe module. + +Widgets are simple moduler templates that can reused +in multiple places. These are like macros, but accessing +them will be a lot easier. + +The widgets will be provided +""" +import frappe +from frappe.utils.jinja import get_jenv + +# search path for widgets. +# When {{widgets.SomeWidget()}} is called, it looks for +# widgets/SomeWidgets.html in each of these modules. +MODULES = [ + "lms" +] + +def update_website_context(context): + """Adds widgets to the context. + + Called from hooks. + """ + context.widgets = Widgets() + +class Widgets: + """The widget collection. + + This is just a placeholder object and returns the appropriate + widget when accessed using attribute. + + >>> widgets = Widgets() + >>> widgets.HelloWorld(name="World!") + '
Hello, World!
' + """ + def __getattr__(self, name): + if not name.startswith("__"): + return Widget(name) + else: + raise AttributeError(name) + +class Widget: + """The Widget class renders a widget. + + Widget is a reusable template defined in widgets/ directory in + each frappe module. + + >>> w = Widget("HelloWorld") + >>> w(name="World!") + '
Hello, World!
' + """ + def __init__(self, name): + self.name = name + + def __call__(self, **kwargs): + # the widget could be in any of the modules + paths = [f"{module}/widgets/{self.name}.html" for module in MODULES] + env = get_jenv() + return env.get_or_select_template(paths).render(kwargs)