Package: jembe
Jembe Web FrameworkJembe 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 sitehttps://jembe.ioQuickstartInstall Jembe FrameworkJembe requiresPython 3.8or above.# Create project directory$mkdirmyproject
$cdmyproject# Create Python virtual enviroment and activate it$python-mvenv.venv
$..venv/bin/activate# Install Jembe framework in newly created vritual enviroment$pipinstalljembe# Start a new project with the premade project template$jembestartproject# Install developer dependencies in a virtual environment$pipinstall-e.[dev]# Run application$flaskrunWith broswer openhttp://localhost:5000to view newly created jembe application.Following examples assumes that the Jembe project is named'myproject'and it's created with$ jembe startprojectcommand.Hello World ExampleCreate a simple Component to render a static HTML page.myproject/pages/hello_world.pyfromjembeimportComponentfrommyproject.appimportjmb@jmb.page('hello')classHellowWorld(Component):passmyproject/templates/hello.html<html><body><h1>Hello World!</h1><script src="{{url_for('jembe.static',filename='js/jembe.js')}}"></script></body></html>Inmyproject/pages/__init__.pyaddfrom .hello_world import HelloWorld.Visithttp://localhost:5000/hello.Making Hello World DynamicUse Componentstate variableto represent the current state of the Component.Allow a user to update Componentstateby interacting with HTML input field.myproject/pages/hello_world.pyfromjembeimportComponentfrommyproject.appimportjmb@jmb.page('hello')classHellowWorld(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.Firstscripttag is required only on Root/Page component, aka@jmb.page(..)Component;Secondscripttag is required byjembe startprojecttemplate to add CSRF protection, and it is added only to Root/Page component;Counter ExampleDefines componentactions.Executeactionswhen an user press button inside component HTML.Creates complex pages by nesting multiple components.myproject/pages/counter.pyfromjembeimportComponent,action,configfrommyproject.appimportjmbclassCounter(Component):def__init__(self,count:int=0):super().__init__()@actiondefincrease(self):self.state.count+=1@actiondefdecrease(self):self.state.count-=1@jmb.page("counter",Component.Config(components={"counter":Counter}))classCounterPage(Component):passInmyproject/pages/__init__.pyaddfrom .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 ExampleChanges 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.pyfromjembeimportComponent,Event,action,config,listenerfrommyproject.appimportjmb@config(Component.Config(changes_url=False))classCounter(Component):def__init__(self,count:int=0):super().__init__()@actiondefincrease(self):self.state.count+=1self.emit("updateSum",value=1)@actiondefdecrease(self):self.state.count-=1self.emit("updateSum",value=-1)@config(Component.Config(changes_url=False))classCounterSum(Component):def__init__(self,sum:int=0):super().__init__()@listener(event="updateSum")defon_update_sum(self,event:"Event"):self.state.sum+=event.params["value"]@jmb.page('multicount',Component.Config(components={"counter":Counter,"sum":CounterSum,}))classMultiCountPage(Component):passInmyproject/pages/__init__.pyaddfrom .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.LicenseJembe Web Framework
Copyright (C) 2021 BlokKodinfo@blokkod.meThis 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, seehttps://www.gnu.org/licenses/.