Added first controls

This commit is contained in:
2025-11-26 20:53:12 +01:00
parent 459c89bae2
commit ce5328fe34
68 changed files with 37849 additions and 87048 deletions

View File

@@ -1,3 +1,4 @@
import inspect
import uuid
from typing import Optional
@@ -29,20 +30,23 @@ class BaseCommand:
self.description = description
self._htmx_extra = {}
self._bindings = []
self._ft = None
# register the command
CommandsManager.register(self)
def get_htmx_params(self):
return self._htmx_extra | {
return {
"hx-post": f"{ROUTE_ROOT}{Routes.Commands}",
"hx-vals": f'{{"c_id": "{self.id}"}}',
}
"hx-swap": "outerHTML",
"hx-vals": {"c_id": f"{self.id}"},
} | self._htmx_extra
def execute(self):
def execute(self, client_response: dict = None):
raise NotImplementedError
def htmx(self, target="this", swap="innerHTML"):
def htmx(self, target: Optional[str] = "this", swap="outerHTML", trigger=None):
# Note that the default value is the same than in get_htmx_params()
if target is None:
self._htmx_extra["hx-swap"] = "none"
elif target != "this":
@@ -50,8 +54,12 @@ class BaseCommand:
if swap is None:
self._htmx_extra["hx-swap"] = "none"
elif swap != "innerHTML":
elif swap != "outerHTML":
self._htmx_extra["hx-swap"] = swap
if trigger is not None:
self._htmx_extra["hx-trigger"] = trigger
return self
def bind_ft(self, ft):
@@ -61,6 +69,7 @@ class BaseCommand:
:param ft:
:return:
"""
self._ft = ft
htmx = self.get_htmx_params()
ft.attrs |= htmx
return ft
@@ -83,6 +92,16 @@ class BaseCommand:
self._htmx_extra["hx-swap"] = "none"
return self
@property
def url(self):
return f"{ROUTE_ROOT}{Routes.Commands}?c_id={self.id}"
def get_ft(self):
return self._ft
def __str__(self):
return f"Command({self.name})"
class Command(BaseCommand):
@@ -107,10 +126,24 @@ class Command(BaseCommand):
def __init__(self, name, description, callback, *args, **kwargs):
super().__init__(name, description)
self.callback = callback
self.callback_parameters = dict(inspect.signature(callback).parameters)
self.args = args
self.kwargs = kwargs
def execute(self):
def _convert(self, key, value):
if key in self.callback_parameters:
param = self.callback_parameters[key]
if param.annotation == bool:
return value == "true"
elif param.annotation == int:
return int(value)
elif param.annotation == float:
return float(value)
elif param.annotation == list:
return value.split(",")
return value
def execute(self, client_response: dict = None):
ret_from_bindings = []
def binding_result_callback(attr, old, new, results):
@@ -119,21 +152,41 @@ class Command(BaseCommand):
for data in self._bindings:
add_event_listener(ObservableEvent.AFTER_PROPERTY_CHANGE, data, "", binding_result_callback)
ret = self.callback(*self.args, **self.kwargs)
new_kwargs = self.kwargs.copy()
if client_response:
for k, v in client_response.items():
if k in self.callback_parameters:
new_kwargs[k] = self._convert(k, v)
if 'client_response' in self.callback_parameters:
new_kwargs['client_response'] = client_response
ret = self.callback(*self.args, **new_kwargs)
for data in self._bindings:
remove_event_listener(ObservableEvent.AFTER_PROPERTY_CHANGE, data, "", binding_result_callback)
# Set the hx-swap-oob attribute on all elements returned by the callback
if isinstance(ret, (list, tuple)):
for r in ret[1:]:
if hasattr(r, 'attrs') and r.get("id", None) is not None:
r.attrs["hx-swap-oob"] = r.attrs.get("hx-swap-oob", "true")
if not ret_from_bindings:
return ret
if isinstance(ret, list):
return ret + ret_from_bindings
if isinstance(ret, (list, tuple)):
return list(ret) + ret_from_bindings
else:
return [ret] + ret_from_bindings
class LambdaCommand(Command):
def __init__(self, delegate, name="LambdaCommand", description="Lambda Command"):
super().__init__(name, description, delegate)
self.htmx(target=None)
def __str__(self):
return f"Command({self.name})"
def execute(self, client_response: dict = None):
return self.callback(client_response)
class CommandsManager: