Compare commits

...

1 Commits

Author SHA1 Message Date
Anand Chitipothu
5feeb4ca0c feat: widgets interface
Widgets are reusable jinja templates which can be used in other
themplates. Widgets are written in widgets/ directory in every frappe
module and can be accessed as `{{ widgets.WidgetName(...) }}` from any
template.
2021-04-29 10:37:36 +05:30
4 changed files with 92 additions and 0 deletions

View File

@@ -169,3 +169,5 @@ profile_rules = [
]
website_route_rules = primary_rules + whitelist_rules + profile_rules
update_website_context = 'community.widgets.update_website_context'

View File

@@ -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") }}
#}
<div class="hello">
Hello, <em>{{ name }}</em>!
</div>

16
community/test_widgets.py Normal file
View File

@@ -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"

60
community/widgets.py Normal file
View File

@@ -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!")
'<div>Hello, World!</div>'
"""
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!")
'<div>Hello, World!</div>'
"""
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)