I can bind elements
This commit is contained in:
114
src/myfasthtml/core/bindings.py
Normal file
114
src/myfasthtml/core/bindings.py
Normal file
@@ -0,0 +1,114 @@
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from fasthtml.fastapp import fast_app
|
||||
from myutils.observable import make_observable, bind, collect_return_values
|
||||
|
||||
from myfasthtml.core.constants import Routes, ROUTE_ROOT
|
||||
from myfasthtml.core.utils import get_default_attr
|
||||
|
||||
bindings_app, bindings_rt = fast_app()
|
||||
logger = logging.getLogger("Bindings")
|
||||
|
||||
|
||||
class Binding:
|
||||
def __init__(self, data, attr=None, ft=None, ft_name=None, ft_attr=None):
|
||||
"""
|
||||
Creates a new binding object between a data object used as a pivot and an HTML element.
|
||||
The same pivot object must be used for different bindings.
|
||||
This will allow the binding between the HTML elements
|
||||
|
||||
:param data: object used as a pivot
|
||||
:param attr: attribute of the data object
|
||||
:param ft: HTML element to bind to
|
||||
:param ft_name: name of the HTML element to bind to (send by the form)
|
||||
:param ft_attr: value of the attribute to bind to (send by the form)
|
||||
"""
|
||||
self.id = uuid.uuid4()
|
||||
self.htmx_extra = {}
|
||||
self.data = data
|
||||
self.data_attr = attr or get_default_attr(data)
|
||||
self.ft = self._safe_ft(ft)
|
||||
self.ft_name = ft_name
|
||||
self.ft_attr = ft_attr
|
||||
|
||||
make_observable(self.data)
|
||||
bind(self.data, self.data_attr, self.notify)
|
||||
|
||||
# register the command
|
||||
BindingsManager.register(self)
|
||||
|
||||
def bind_ft(self, ft, name, attr=None):
|
||||
"""
|
||||
Update the elements to bind to
|
||||
:param ft:
|
||||
:param name:
|
||||
:param attr:
|
||||
:return:
|
||||
"""
|
||||
self.ft = self._safe_ft(ft)
|
||||
self.ft_name = name
|
||||
self.ft_attr = attr
|
||||
|
||||
def get_htmx_params(self):
|
||||
return self.htmx_extra | {
|
||||
"hx-post": f"{ROUTE_ROOT}{Routes.Bindings}",
|
||||
"hx-vals": f'{{"b_id": "{self.id}"}}',
|
||||
}
|
||||
|
||||
def notify(self, old, new):
|
||||
logger.debug(f"Binding '{self.id}': Changing from '{old}' to '{new}'")
|
||||
if self.ft_attr is None:
|
||||
self.ft.children = (new,)
|
||||
else:
|
||||
self.ft.attrs[self.ft_attr] = new
|
||||
|
||||
self.ft.attrs["hx-swap-oob"] = "true"
|
||||
return self.ft
|
||||
|
||||
def update(self, values: dict):
|
||||
logger.debug(f"Binding '{self.id}': Updating with {values=}.")
|
||||
for key, value in values.items():
|
||||
if key == self.ft_name:
|
||||
setattr(self.data, self.data_attr, value)
|
||||
res = collect_return_values(self.data)
|
||||
return res
|
||||
|
||||
else:
|
||||
logger.debug(f"Nothing to trigger in {values}.")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _safe_ft(ft):
|
||||
"""
|
||||
Make sure the ft has an id.
|
||||
:param ft:
|
||||
:return:
|
||||
"""
|
||||
if ft is None:
|
||||
return None
|
||||
|
||||
if ft.attrs.get("id", None) is None:
|
||||
ft.attrs["id"] = str(uuid.uuid4())
|
||||
return ft
|
||||
|
||||
def htmx(self, trigger=None):
|
||||
if trigger:
|
||||
self.htmx_extra["hx-trigger"] = trigger
|
||||
return self
|
||||
|
||||
class BindingsManager:
|
||||
bindings = {}
|
||||
|
||||
@staticmethod
|
||||
def register(binding: Binding):
|
||||
BindingsManager.bindings[str(binding.id)] = binding
|
||||
|
||||
@staticmethod
|
||||
def get_binding(binding_id: str) -> Optional[Binding]:
|
||||
return BindingsManager.bindings.get(str(binding_id))
|
||||
|
||||
@staticmethod
|
||||
def reset():
|
||||
return BindingsManager.bindings.clear()
|
||||
Reference in New Issue
Block a user