Jembe Web Framework
Project description
Jembe Web Framework
Jembe is a Python Web Framework for developing modern web applications, build on top of Flask, and designed with the following goals:
- Web Frontend/UI is created by combing and nesting configurable, reusable, and adaptable UI components;
- UI Component is responsible for rendering one part of a web page and handling all user interaction regarding that part of the page;
- New UI components are created by extending Component class, and writing associated Jinja2 template;
- There should be no reason to think about, consider or implement the logic for:
- Handling HTTP request-response cycle;
- URL Routing;
- Handling any "low level" web/HTTP API;
- Complex UI behaviors and user interactions are handled with minimal javascript code, using server-side HTML rendering and partial page updating, allowing the majority of UI and all business logic to be written in Python and executed on the server;
- Once a set of "basic" UI components is created Developer should be able to stay focused primarily on "business" logic and write new UI/Frontend logic only for specific use cases;
Official web site https://jembe.io
Quickstart
Install Jembe Framework
Jembe requires Python 3.8 or above.
# Create project directory
$ mkdir myproject
$ cd myproject
# Create Python virtual enviroment and activate it
$ python -m venv .venv
$ . .venv/bin/activate
# Install Jembe framework in newly created vritual enviroment
$ pip install jembe
# Start a new project with the premade project template
$ jembe startproject
# Install developer dependencies in a virtual environment
$ pip install -e .[dev]
# Run application
$ flask run
With broswer open http://localhost:5000 to view newly created jembe application.
Following examples assumes that the Jembe project is named 'myproject' and it's created with
$ jembe startproject
command.
Hello World Example
Create a simple Component to render a static HTML page.
myproject/pages/hello_world.py
from jembe import Component
from myproject.app import jmb
@jmb.page('hello')
class HellowWorld(Component):
pass
myproject/templates/hello.html
<html>
<body>
<h1>Hello World!</h1>
<script src="{{ url_for('jembe.static', filename='js/jembe.js') }}"></script>
</body>
</html>
In myproject/pages/__init__.py
add from .hello_world import HelloWorld
.
Visit http://localhost:5000/hello
.
Making Hello World Dynamic
- Use Component state variable to represent the current state of the Component.
- Allow a user to update Component state by interacting with HTML input field.
myproject/pages/hello_world.py
from jembe import Component
from myproject.app import jmb
@jmb.page('hello')
class HellowWorld(Component):
def __init__(self, name: str = "World"):
super().__init__()
myproject/templates/hello.html
<html>
<body>
<h1>Hello {{name}}!</h1>
<input jmb-on:keydown.debounce="name = $self.value" value="{{name}}">
<script src="{{ url_for('jembe.static', filename='js/jembe.js') }}"></script>
<script defer>
{# Adds CSRF protection to Jembe AJAX requests #}
window.addEventListener('DOMContentLoaded', function(event){
window.jembeClient.addXRequestHeaderGenerator(function () {
return {'X-CSRFToken': window.jembeClient.getCookie("_csrf_token")};
})
})
</script>
</body>
</html>
Notice that the input field doesn't lose focus when the page is updated.
- First
script
tag is required only on Root/Page component, aka@jmb.page(..)
Component;- Second
script
tag is required byjembe startproject
template to add CSRF protection, and it is added only to Root/Page component;
Counter Example
- Defines component actions.
- Execute actions when an user press button inside component HTML.
- Creates complex pages by nesting multiple components.
myproject/pages/counter.py
from jembe import Component, action, config
from myproject.app import jmb
class Counter(Component):
def __init__(self, count:int = 0):
super().__init__()
@action
def increase(self):
self.state.count += 1
@action
def decrease(self):
self.state.count -= 1
@jmb.page(
"counter",
Component.Config(
components={
"counter": Counter
}
)
)
class CounterPage(Component):
pass
In myproject/pages/__init__.py
add from .counter import CounterPage
.
myproject/templates/counter/counter.html
<h2>Counter</h2>
<div>
Value: {{count}}
<button jmb-on:click="decrease()" type="button">-</button>
<button jmb-on:click="increase()" type="button">+</button>
</div>
myproject/templates/counter.html
<html>
<body>
{{component('counter')}}
<script src="{{ url_for('jembe.static', filename='js/jembe.js') }}"></script>
<script defer>
{# Adds CSRF protection to Jembe AJAX requests #}
window.addEventListener('DOMContentLoaded', function(event){
window.jembeClient.addXRequestHeaderGenerator(function () {
return {'X-CSRFToken': window.jembeClient.getCookie("_csrf_token")};
})
})
</script>
</body>
</html>
When increasing/decreasing counter, Jembe only renderers and updated Counter Component HTML, the rest of the HTML on the page is not changed.
Multiple Counters Example
- Changes component configuration, instructing Jembe that URL should not be changed when the component is displayed on the page;
- Communicate between components using events and listeners.
- Use multiple instances of the same component on a page.
myproject/pages/multi_counter.py
from jembe import Component, Event, action, config, listener
from myproject.app import jmb
@config(Component.Config(changes_url=False))
class Counter(Component):
def __init__(self, count:int = 0):
super().__init__()
@action
def increase(self):
self.state.count += 1
self.emit("updateSum", value=1)
@action
def decrease(self):
self.state.count -= 1
self.emit("updateSum", value=-1)
@config(Component.Config(changes_url=False))
class CounterSum(Component):
def __init__(self, sum:int = 0):
super().__init__()
@listener(event="updateSum")
def on_update_sum(self, event:"Event"):
self.state.sum += event.params["value"]
@jmb.page(
'multicount',
Component.Config(
components={
"counter": Counter,
"sum": CounterSum,
}
)
)
class MultiCountPage(Component):
pass
In myproject/pages/__init__.py
add from .multi_counter import MultiCountPage
.
myproject/templates/multicount/counter.html
<div>
Counter {{key}}: {{count}}
<button jmb-on:click="decrease()" type="button">-</button>
<button jmb-on:click="increase()" type="button">+</button>
</div>
myproject/templates/multicount/sum.html
<div>
<strong>Total: {{sum}}</strong>
</div>
myproject/templates/multicount.html
<html>
<body>
{{component('counter').key('a')}}
{{component('counter').key('b')}}
{{component('counter').key('c')}}
{{component('sum')}}
<script src="{{ url_for('jembe.static', filename='js/jembe.js') }}"></script>
<script defer>
{# Adds CSRF protection to Jembe AJAX requests #}
window.addEventListener('DOMContentLoaded', function(event){
window.jembeClient.addXRequestHeaderGenerator(function () {
return {'X-CSRFToken': window.jembeClient.getCookie("_csrf_token")};
})
})
</script>
</body>
</html>
When the user changes the value of one Counter Component, only that Counter and CounterSum Component HTML are redisplayed and updated.
License
Jembe Web Framework Copyright (C) 2021 BlokKod info@blokkod.me
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this program. If not, see https://www.gnu.org/licenses/.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file jembe-0.3.15.tar.gz
.
File metadata
- Download URL: jembe-0.3.15.tar.gz
- Upload date:
- Size: 273.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2551f035f5bb02e2e77defc7094c02bd55349ac2c8cc2498f206e75ff58f5cda |
|
MD5 | d2fd1349594543798b887c48f047b20a |
|
BLAKE2b-256 | 7af59cdbe1eee81b98aef793cb3de2c515260af67941c53885c07002ac3bfaec |
File details
Details for the file jembe-0.3.15-py3-none-any.whl
.
File metadata
- Download URL: jembe-0.3.15-py3-none-any.whl
- Upload date:
- Size: 257.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.5
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5addd8224cbbb0caa42d795a8b2363882333ee480c6fb3a2db78a135c9fe5db0 |
|
MD5 | 9d8a35b9d88cbc213a326fbb47ea625b |
|
BLAKE2b-256 | 5df266f4bdc57c5c590cd2dd9299c13debd0833a4ed8bfee216ac6f9c8fb32a3 |